<!-- CANARY: REQ=REQ-DOCS-001; FEATURE="Docs"; ASPECT=Documentation; STATUS=TESTED; OWNER=docs; UPDATED=2026-01-28 -->
<h2 id="migrating-from-postgresql-to-geode" class="position-relative d-flex align-items-center group">
<span>Migrating from PostgreSQL to Geode</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="migrating-from-postgresql-to-geode"
aria-haspopup="dialog"
aria-label="Share link: Migrating from PostgreSQL to Geode">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h2><div id="headingShareModal" class="heading-share-modal" role="dialog" aria-modal="true" aria-labelledby="headingShareTitle" hidden>
<div class="hsm-dialog" role="document">
<div class="hsm-header">
<h2 id="headingShareTitle" class="h6 mb-0 fw-bold">Share this section</h2>
<button type="button" class="hsm-close" aria-label="Close">
<i class="fa-solid fa-xmark"></i>
</button>
</div>
<div class="hsm-body">
<label for="headingShareInput" class="form-label small text-muted mb-1 text-uppercase fw-bold" style="font-size: 0.7rem; letter-spacing: 0.5px;">Permalink</label>
<div class="input-group mb-4 hsm-url-group">
<input id="headingShareInput" type="text" class="form-control font-monospace" readonly aria-readonly="true" style="font-size: 0.85rem;" />
<button class="btn btn-primary hsm-copy" type="button" aria-label="Copy" title="Copy">
<i class="fa-duotone fa-clipboard" aria-hidden="true"></i>
</button>
</div>
<div class="small fw-bold mb-2 text-muted text-uppercase" style="font-size: 0.7rem; letter-spacing: 0.5px;">Share via</div>
<div class="hsm-share-grid">
<a id="share-twitter" class="btn btn-outline-secondary w-100" target="_blank" rel="noopener noreferrer">
<i class="fa-brands fa-twitter me-2"></i>Twitter
</a>
<a id="share-linkedin" class="btn btn-outline-secondary w-100" target="_blank" rel="noopener noreferrer">
<i class="fa-brands fa-linkedin me-2"></i>LinkedIn
</a>
<a id="share-facebook" class="btn btn-outline-secondary w-100" target="_blank" rel="noopener noreferrer">
<i class="fa-brands fa-facebook me-2"></i>Facebook
</a>
</div>
</div>
</div>
</div>
<style>
.heading-share-modal {
position: fixed;
inset: 0;
display: flex;
justify-content: center;
align-items: center;
background: rgba(0, 0, 0, 0.6);
z-index: 1050;
padding: 1rem;
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
}
.heading-share-modal[hidden] { display: none !important; }
.hsm-dialog {
max-width: 420px;
width: 100%;
background: var(--bs-body-bg, #fff);
color: var(--bs-body-color, #212529);
border: 1px solid var(--bs-border-color, rgba(0,0,0,0.1));
border-radius: 1rem;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
overflow: hidden;
animation: hsm-fade-in 0.2s ease-out;
}
@keyframes hsm-fade-in {
from { opacity: 0; transform: scale(0.95); }
to { opacity: 1; transform: scale(1); }
}
[data-bs-theme="dark"] .hsm-dialog {
background: #1e293b;
border-color: rgba(255,255,255,0.1);
color: #f8f9fa;
}
.hsm-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 1.5rem;
border-bottom: 1px solid var(--bs-border-color, rgba(0,0,0,0.1));
background: rgba(0,0,0,0.02);
}
[data-bs-theme="dark"] .hsm-header {
background: rgba(255,255,255,0.02);
border-color: rgba(255,255,255,0.1);
}
.hsm-close {
background: transparent;
border: none;
color: inherit;
opacity: 0.5;
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
font-size: 1.2rem;
line-height: 1;
transition: opacity 0.2s;
}
.hsm-close:hover {
opacity: 1;
}
.hsm-body {
padding: 1.5rem;
}
.hsm-url-group {
display: flex !important;
align-items: stretch;
}
.hsm-url-group .form-control {
flex: 1;
min-width: 0;
margin: 0;
background: var(--bs-secondary-bg, #f8f9fa);
border-color: var(--bs-border-color, #dee2e6);
border-top-right-radius: 0;
border-bottom-right-radius: 0;
height: 42px;
}
.hsm-url-group .btn {
flex: 0 0 auto;
margin: 0;
margin-left: -1px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
height: 42px;
display: flex;
align-items: center;
justify-content: center;
padding: 0 1.25rem;
z-index: 2;
}
[data-bs-theme="dark"] .hsm-url-group .form-control {
background: #0f172a;
border-color: #334155;
color: #e2e8f0;
}
.hsm-share-grid {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.hsm-share-grid .btn {
display: flex;
align-items: center;
justify-content: center;
font-size: 0.9rem;
padding: 0.6rem;
border-color: var(--bs-border-color);
width: 100%;
}
[data-bs-theme="dark"] .hsm-share-grid .btn {
color: #e2e8f0;
border-color: #475569;
}
[data-bs-theme="dark"] .hsm-share-grid .btn:hover {
background: #334155;
border-color: #cbd5e1;
}
</style>
<script>
(function(){
const modal = document.getElementById('headingShareModal');
if(!modal) return;
const input = modal.querySelector('#headingShareInput');
const copyBtn = modal.querySelector('.hsm-copy');
const twitter = modal.querySelector('#share-twitter');
const linkedin = modal.querySelector('#share-linkedin');
const facebook = modal.querySelector('#share-facebook');
const closeBtn = modal.querySelector('.hsm-close');
let lastFocus=null;
let trapBound=false;
function buildUrl(id){ return window.location.origin + window.location.pathname + '#' + id; }
function isOpen(){ return !modal.hasAttribute('hidden'); }
function hydrate(id){
const url=buildUrl(id);
input.value=url;
const enc=encodeURIComponent(url);
const text=encodeURIComponent(document.title);
if(twitter) twitter.href=`https://twitter.com/intent/tweet?url=${enc}&text=${text}`;
if(linkedin) linkedin.href=`https://www.linkedin.com/sharing/share-offsite/?url=${enc}`;
if(facebook) facebook.href=`https://www.facebook.com/sharer/sharer.php?u=${enc}`;
}
function openModal(id){
lastFocus=document.activeElement;
hydrate(id);
if(!isOpen()){
modal.removeAttribute('hidden');
}
requestAnimationFrame(()=>{ input.focus(); });
trapFocus();
}
function closeModal(){
if(!isOpen()) return;
modal.setAttribute('hidden','');
if(lastFocus && typeof lastFocus.focus==='function') lastFocus.focus();
}
function copyCurrent(){
try{ navigator.clipboard.writeText(input.value).then(()=>feedback(true),()=>fallback()); }
catch(e){ fallback(); }
}
function fallback(){ input.select(); try{ document.execCommand('copy'); feedback(true);}catch(e){ feedback(false);} }
function feedback(ok){ if(!copyBtn) return; const icon=copyBtn.querySelector('i'); if(!icon) return; const prev=copyBtn.getAttribute('data-prev')||icon.className; if(!copyBtn.getAttribute('data-prev')) copyBtn.setAttribute('data-prev',prev); icon.className= ok ? 'fa-duotone fa-clipboard-check':'fa-duotone fa-circle-exclamation'; setTimeout(()=>{ icon.className=prev; },1800); }
function handleShareClick(e){ e.preventDefault(); const btn=e.currentTarget; const id=btn.getAttribute('data-share-target'); if(id) openModal(id); }
function bindShareButtons(){
document.querySelectorAll('.h-share').forEach(btn=>{
if(!btn.dataset.hShareBound){ btn.addEventListener('click', handleShareClick); btn.dataset.hShareBound='1'; }
});
}
bindShareButtons();
if(document.readyState==='loading'){
document.addEventListener('DOMContentLoaded', bindShareButtons);
} else {
requestAnimationFrame(bindShareButtons);
}
document.addEventListener('click', function(e){
const shareBtn=e.target.closest && e.target.closest('.h-share');
if(shareBtn && !shareBtn.dataset.hShareBound){ handleShareClick.call(shareBtn, e); }
}, true);
document.addEventListener('click', e=>{
if(e.target===modal) closeModal();
if(e.target.closest && e.target.closest('.hsm-close')){ e.preventDefault(); closeModal(); }
if(copyBtn && (e.target===copyBtn || (e.target.closest && e.target.closest('.hsm-copy')))) { e.preventDefault(); copyCurrent(); }
});
document.addEventListener('keydown', e=>{ if(e.key==='Escape' && isOpen()) closeModal(); });
function trapFocus(){
if(trapBound) return;
trapBound=true;
modal.addEventListener('keydown', f=>{ if(f.key==='Tab' && isOpen()){ const focusable=[...modal.querySelectorAll('a[href],button,input,textarea,select,[tabindex]:not([tabindex="-1"])')].filter(el=>!el.hasAttribute('disabled')); if(!focusable.length) return; const first=focusable[0]; const last=focusable[focusable.length-1]; if(f.shiftKey && document.activeElement===first){ f.preventDefault(); last.focus(); } else if(!f.shiftKey && document.activeElement===last){ f.preventDefault(); first.focus(); } } });
}
if(closeBtn) closeBtn.addEventListener('click', e=>{ e.preventDefault(); closeModal(); });
})();
</script><p>This guide provides a comprehensive approach to migrating from PostgreSQL to Geode. Unlike migrating between similar databases, moving from a relational model to a graph model requires rethinking how you structure and query your data.</p>
<h3 id="migration-overview" class="position-relative d-flex align-items-center group">
<span>Migration Overview</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="migration-overview"
aria-haspopup="dialog"
aria-label="Share link: Migration Overview">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="when-to-use-a-graph-database" class="position-relative d-flex align-items-center group">
<span>When to Use a Graph Database</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="when-to-use-a-graph-database"
aria-haspopup="dialog"
aria-label="Share link: When to Use a Graph Database">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Graph databases excel when:</p>
<ul>
<li><strong>Relationships are first-class citizens</strong>: Your queries traverse multiple relationships</li>
<li><strong>Schema is flexible</strong>: New relationship types emerge over time</li>
<li><strong>Many-to-many relationships dominate</strong>: Junction tables become unwieldy</li>
<li><strong>Path queries are common</strong>: Finding connections between entities</li>
</ul>
<h4 id="when-to-keep-postgresql" class="position-relative d-flex align-items-center group">
<span>When to Keep PostgreSQL</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="when-to-keep-postgresql"
aria-haspopup="dialog"
aria-label="Share link: When to Keep PostgreSQL">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Consider keeping PostgreSQL for:</p>
<ul>
<li>Simple CRUD operations with fixed schemas</li>
<li>Heavy aggregation/reporting workloads</li>
<li>Strong ACID requirements with complex constraints</li>
<li>Well-defined, stable relational structures</li>
</ul>
<h4 id="hybrid-approach" class="position-relative d-flex align-items-center group">
<span>Hybrid Approach</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="hybrid-approach"
aria-haspopup="dialog"
aria-label="Share link: Hybrid Approach">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Many organizations run both:</p>
<ul>
<li>PostgreSQL for transactional data and reporting</li>
<li>Geode for relationship-heavy queries and traversals</li>
</ul>
<h3 id="relational-to-graph-model-conversion" class="position-relative d-flex align-items-center group">
<span>Relational to Graph Model Conversion</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="relational-to-graph-model-conversion"
aria-haspopup="dialog"
aria-label="Share link: Relational to Graph Model Conversion">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="core-concepts-mapping" class="position-relative d-flex align-items-center group">
<span>Core Concepts Mapping</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="core-concepts-mapping"
aria-haspopup="dialog"
aria-label="Share link: Core Concepts Mapping">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><table>
<thead>
<tr>
<th>Relational Concept</th>
<th>Graph Equivalent</th>
</tr>
</thead>
<tbody>
<tr>
<td>Table</td>
<td>Node Label</td>
</tr>
<tr>
<td>Row</td>
<td>Node</td>
</tr>
<tr>
<td>Column</td>
<td>Property</td>
</tr>
<tr>
<td>Primary Key</td>
<td>Node ID property</td>
</tr>
<tr>
<td>Foreign Key</td>
<td>Relationship</td>
</tr>
<tr>
<td>Junction Table</td>
<td>Relationship (with properties)</td>
</tr>
<tr>
<td>View</td>
<td>Stored Query</td>
</tr>
</tbody>
</table>
<h4 id="example-e-commerce-schema" class="position-relative d-flex align-items-center group">
<span>Example: E-Commerce Schema</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="example-e-commerce-schema"
aria-haspopup="dialog"
aria-label="Share link: Example: E-Commerce Schema">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>PostgreSQL Schema</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">customers</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="nb">SERIAL</span><span class="w"> </span><span class="k">PRIMARY</span><span class="w"> </span><span class="k">KEY</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">255</span><span class="p">)</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">email</span><span class="w"> </span><span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">255</span><span class="p">)</span><span class="w"> </span><span class="k">UNIQUE</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">created_at</span><span class="w"> </span><span class="k">TIMESTAMP</span><span class="w"> </span><span class="k">DEFAULT</span><span class="w"> </span><span class="n">NOW</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">products</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="nb">SERIAL</span><span class="w"> </span><span class="k">PRIMARY</span><span class="w"> </span><span class="k">KEY</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">255</span><span class="p">)</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">price</span><span class="w"> </span><span class="nb">DECIMAL</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">)</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">category_id</span><span class="w"> </span><span class="nb">INTEGER</span><span class="w"> </span><span class="k">REFERENCES</span><span class="w"> </span><span class="n">categories</span><span class="p">(</span><span class="n">id</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">categories</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="nb">SERIAL</span><span class="w"> </span><span class="k">PRIMARY</span><span class="w"> </span><span class="k">KEY</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">255</span><span class="p">)</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">parent_id</span><span class="w"> </span><span class="nb">INTEGER</span><span class="w"> </span><span class="k">REFERENCES</span><span class="w"> </span><span class="n">categories</span><span class="p">(</span><span class="n">id</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">orders</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="nb">SERIAL</span><span class="w"> </span><span class="k">PRIMARY</span><span class="w"> </span><span class="k">KEY</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">customer_id</span><span class="w"> </span><span class="nb">INTEGER</span><span class="w"> </span><span class="k">REFERENCES</span><span class="w"> </span><span class="n">customers</span><span class="p">(</span><span class="n">id</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">order_date</span><span class="w"> </span><span class="k">TIMESTAMP</span><span class="w"> </span><span class="k">DEFAULT</span><span class="w"> </span><span class="n">NOW</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">status</span><span class="w"> </span><span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">50</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">order_items</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="nb">SERIAL</span><span class="w"> </span><span class="k">PRIMARY</span><span class="w"> </span><span class="k">KEY</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">order_id</span><span class="w"> </span><span class="nb">INTEGER</span><span class="w"> </span><span class="k">REFERENCES</span><span class="w"> </span><span class="n">orders</span><span class="p">(</span><span class="n">id</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">product_id</span><span class="w"> </span><span class="nb">INTEGER</span><span class="w"> </span><span class="k">REFERENCES</span><span class="w"> </span><span class="n">products</span><span class="p">(</span><span class="n">id</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">quantity</span><span class="w"> </span><span class="nb">INTEGER</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">unit_price</span><span class="w"> </span><span class="nb">DECIMAL</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">)</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">reviews</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="nb">SERIAL</span><span class="w"> </span><span class="k">PRIMARY</span><span class="w"> </span><span class="k">KEY</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">customer_id</span><span class="w"> </span><span class="nb">INTEGER</span><span class="w"> </span><span class="k">REFERENCES</span><span class="w"> </span><span class="n">customers</span><span class="p">(</span><span class="n">id</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">product_id</span><span class="w"> </span><span class="nb">INTEGER</span><span class="w"> </span><span class="k">REFERENCES</span><span class="w"> </span><span class="n">products</span><span class="p">(</span><span class="n">id</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">rating</span><span class="w"> </span><span class="nb">INTEGER</span><span class="w"> </span><span class="k">CHECK</span><span class="w"> </span><span class="p">(</span><span class="n">rating</span><span class="w"> </span><span class="k">BETWEEN</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="mi">5</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">comment</span><span class="w"> </span><span class="nb">TEXT</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">created_at</span><span class="w"> </span><span class="k">TIMESTAMP</span><span class="w"> </span><span class="k">DEFAULT</span><span class="w"> </span><span class="n">NOW</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">);</span><span class="w">
</span></span></span></code></pre></div><p><strong>Geode Graph Model</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">//</span><span class="w"> </span><span class="py">Nodes</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(:</span><span class="nc">Customer</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">,</span><span class="w"> </span><span class="py">name</span><span class="p">,</span><span class="w"> </span><span class="py">email</span><span class="p">,</span><span class="w"> </span><span class="py">created_at</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(:</span><span class="nc">Product</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">,</span><span class="w"> </span><span class="py">name</span><span class="p">,</span><span class="w"> </span><span class="py">price</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(:</span><span class="nc">Category</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">,</span><span class="w"> </span><span class="py">name</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(:</span><span class="nc">Order</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">,</span><span class="w"> </span><span class="py">order_date</span><span class="p">,</span><span class="w"> </span><span class="py">status</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="err">//</span><span class="w"> </span><span class="py">Relationships</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(:</span><span class="nc">Customer</span><span class="p">)</span><span class="err">-</span><span class="p">[:</span><span class="nc">PLACED</span><span class="p">]</span><span class="err">-></span><span class="p">(:</span><span class="nc">Order</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(:</span><span class="nc">Order</span><span class="p">)</span><span class="err">-</span><span class="p">[:</span><span class="nc">CONTAINS</span><span class="w"> </span><span class="p">{</span><span class="py">quantity</span><span class="p">,</span><span class="w"> </span><span class="py">unit_price</span><span class="p">}]</span><span class="err">-></span><span class="p">(:</span><span class="nc">Product</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(:</span><span class="nc">Product</span><span class="p">)</span><span class="err">-</span><span class="p">[:</span><span class="nc">IN_CATEGORY</span><span class="p">]</span><span class="err">-></span><span class="p">(:</span><span class="nc">Category</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(:</span><span class="nc">Category</span><span class="p">)</span><span class="err">-</span><span class="p">[:</span><span class="nc">PARENT</span><span class="p">]</span><span class="err">-></span><span class="p">(:</span><span class="nc">Category</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(:</span><span class="nc">Customer</span><span class="p">)</span><span class="err">-</span><span class="p">[:</span><span class="nc">REVIEWED</span><span class="w"> </span><span class="p">{</span><span class="py">rating</span><span class="p">,</span><span class="w"> </span><span class="py">comment</span><span class="p">,</span><span class="w"> </span><span class="py">created_at</span><span class="p">}]</span><span class="err">-></span><span class="p">(:</span><span class="nc">Product</span><span class="p">)</span><span class="w">
</span></span></span></code></pre></div><p><strong>Visual Representation</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"> +-----------+
</span></span><span class="line"><span class="cl"> | Category |
</span></span><span class="line"><span class="cl"> +-----------+
</span></span><span class="line"><span class="cl"> ^
</span></span><span class="line"><span class="cl"> | :PARENT (self-referential)
</span></span><span class="line"><span class="cl"> |
</span></span><span class="line"><span class="cl"> +-----------+
</span></span><span class="line"><span class="cl"> | Category |
</span></span><span class="line"><span class="cl"> +-----------+
</span></span><span class="line"><span class="cl"> ^
</span></span><span class="line"><span class="cl"> | :IN_CATEGORY
</span></span><span class="line"><span class="cl"> |
</span></span><span class="line"><span class="cl">+-----------+ +-----------+ +-----------+
</span></span><span class="line"><span class="cl">| Customer |------>| Order |------>| Product |
</span></span><span class="line"><span class="cl">+-----------+ :PLACED +-----------+ :CONTAINS +-----------+
</span></span><span class="line"><span class="cl"> | ^
</span></span><span class="line"><span class="cl"> | |
</span></span><span class="line"><span class="cl"> +---------------------------------------+
</span></span><span class="line"><span class="cl"> :REVIEWED
</span></span></code></pre></div>
<h3 id="table-to-node-mapping" class="position-relative d-flex align-items-center group">
<span>Table to Node Mapping</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="table-to-node-mapping"
aria-haspopup="dialog"
aria-label="Share link: Table to Node Mapping">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="simple-tables" class="position-relative d-flex align-items-center group">
<span>Simple Tables</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="simple-tables"
aria-haspopup="dialog"
aria-label="Share link: Simple Tables">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>PostgreSQL</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">users</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="nb">SERIAL</span><span class="w"> </span><span class="k">PRIMARY</span><span class="w"> </span><span class="k">KEY</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">username</span><span class="w"> </span><span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">100</span><span class="p">)</span><span class="w"> </span><span class="k">UNIQUE</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">email</span><span class="w"> </span><span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">255</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">age</span><span class="w"> </span><span class="nb">INTEGER</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">active</span><span class="w"> </span><span class="nb">BOOLEAN</span><span class="w"> </span><span class="k">DEFAULT</span><span class="w"> </span><span class="k">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">);</span><span class="w">
</span></span></span></code></pre></div><p><strong>GQL Node Creation</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="py">CREATE</span><span class="w"> </span><span class="p">(:</span><span class="nc">User</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">1</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">username</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">alice</span><span class="err">'</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">email</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">alice</span><span class="nd">@example</span><span class="err">.</span><span class="py">com</span><span class="err">'</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">age</span><span class="p">:</span><span class="w"> </span><span class="nc">30</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">active</span><span class="p">:</span><span class="w"> </span><span class="nc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">})</span><span class="w">
</span></span></span></code></pre></div>
<h4 id="tables-with-enums" class="position-relative d-flex align-items-center group">
<span>Tables with Enums</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="tables-with-enums"
aria-haspopup="dialog"
aria-label="Share link: Tables with Enums">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>PostgreSQL</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">CREATE</span><span class="w"> </span><span class="k">TYPE</span><span class="w"> </span><span class="n">user_role</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">ENUM</span><span class="w"> </span><span class="p">(</span><span class="s1">'admin'</span><span class="p">,</span><span class="w"> </span><span class="s1">'user'</span><span class="p">,</span><span class="w"> </span><span class="s1">'guest'</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">users</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="nb">SERIAL</span><span class="w"> </span><span class="k">PRIMARY</span><span class="w"> </span><span class="k">KEY</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">255</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">role</span><span class="w"> </span><span class="n">user_role</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">);</span><span class="w">
</span></span></span></code></pre></div><p><strong>GQL</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">//</span><span class="w"> </span><span class="py">Option</span><span class="w"> </span><span class="py">1</span><span class="p">:</span><span class="w"> </span><span class="nc">Store</span><span class="w"> </span><span class="py">as</span><span class="w"> </span><span class="py">string</span><span class="w"> </span><span class="py">property</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="p">(:</span><span class="nc">User</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">1</span><span class="p">,</span><span class="w"> </span><span class="py">name</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">Alice</span><span class="err">'</span><span class="p">,</span><span class="w"> </span><span class="py">role</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">admin</span><span class="err">'</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="err">//</span><span class="w"> </span><span class="py">Option</span><span class="w"> </span><span class="py">2</span><span class="p">:</span><span class="w"> </span><span class="nc">Use</span><span class="w"> </span><span class="py">labels</span><span class="w"> </span><span class="py">for</span><span class="w"> </span><span class="py">roles</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="p">(:</span><span class="nc">User</span><span class="p">:</span><span class="nc">Admin</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">1</span><span class="p">,</span><span class="w"> </span><span class="py">name</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">Alice</span><span class="err">'</span><span class="p">})</span><span class="w">
</span></span></span></code></pre></div>
<h4 id="tables-with-arrays" class="position-relative d-flex align-items-center group">
<span>Tables with Arrays</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="tables-with-arrays"
aria-haspopup="dialog"
aria-label="Share link: Tables with Arrays">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>PostgreSQL</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">articles</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="nb">SERIAL</span><span class="w"> </span><span class="k">PRIMARY</span><span class="w"> </span><span class="k">KEY</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">title</span><span class="w"> </span><span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">255</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">tags</span><span class="w"> </span><span class="nb">TEXT</span><span class="p">[]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">);</span><span class="w">
</span></span></span></code></pre></div><p><strong>GQL</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">//</span><span class="w"> </span><span class="py">Option</span><span class="w"> </span><span class="py">1</span><span class="p">:</span><span class="w"> </span><span class="nc">Store</span><span class="w"> </span><span class="py">as</span><span class="w"> </span><span class="py">list</span><span class="w"> </span><span class="py">property</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="p">(:</span><span class="nc">Article</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">1</span><span class="p">,</span><span class="w"> </span><span class="py">title</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">Graph</span><span class="w"> </span><span class="py">Databases</span><span class="err">'</span><span class="p">,</span><span class="w"> </span><span class="py">tags</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="err">'</span><span class="nc">database</span><span class="err">'</span><span class="p">,</span><span class="w"> </span><span class="err">'</span><span class="py">graph</span><span class="err">'</span><span class="p">,</span><span class="w"> </span><span class="err">'</span><span class="py">nosql</span><span class="err">'</span><span class="p">]})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="err">//</span><span class="w"> </span><span class="py">Option</span><span class="w"> </span><span class="py">2</span><span class="p">:</span><span class="w"> </span><span class="nc">Create</span><span class="w"> </span><span class="py">Tag</span><span class="w"> </span><span class="py">nodes</span><span class="w"> </span><span class="py">with</span><span class="w"> </span><span class="py">relationships</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="p">(:</span><span class="nc">Article</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">1</span><span class="p">,</span><span class="w"> </span><span class="py">title</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">Graph</span><span class="w"> </span><span class="py">Databases</span><span class="err">'</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="p">(:</span><span class="nc">Tag</span><span class="w"> </span><span class="p">{</span><span class="py">name</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">database</span><span class="err">'</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="p">(:</span><span class="nc">Tag</span><span class="w"> </span><span class="p">{</span><span class="py">name</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">graph</span><span class="err">'</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">a</span><span class="p">:</span><span class="nc">Article</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">1</span><span class="p">}),</span><span class="w"> </span><span class="p">(</span><span class="py">t</span><span class="p">:</span><span class="nc">Tag</span><span class="w"> </span><span class="p">{</span><span class="py">name</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">database</span><span class="err">'</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="p">(</span><span class="py">a</span><span class="p">)</span><span class="err">-</span><span class="p">[:</span><span class="nc">TAGGED</span><span class="p">]</span><span class="err">-></span><span class="p">(</span><span class="py">t</span><span class="p">)</span><span class="w">
</span></span></span></code></pre></div>
<h4 id="tables-with-json" class="position-relative d-flex align-items-center group">
<span>Tables with JSON</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="tables-with-json"
aria-haspopup="dialog"
aria-label="Share link: Tables with JSON">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>PostgreSQL</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">events</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="nb">SERIAL</span><span class="w"> </span><span class="k">PRIMARY</span><span class="w"> </span><span class="k">KEY</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">255</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">metadata</span><span class="w"> </span><span class="n">JSONB</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">);</span><span class="w">
</span></span></span></code></pre></div><p><strong>GQL</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">//</span><span class="w"> </span><span class="py">Option</span><span class="w"> </span><span class="py">1</span><span class="p">:</span><span class="w"> </span><span class="nc">Store</span><span class="w"> </span><span class="py">as</span><span class="w"> </span><span class="py">map</span><span class="w"> </span><span class="py">property</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="p">(:</span><span class="nc">Event</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">1</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">name</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">PageView</span><span class="err">'</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">metadata</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="nc">browser</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">Chrome</span><span class="err">'</span><span class="p">,</span><span class="w"> </span><span class="py">os</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">Windows</span><span class="err">'</span><span class="p">,</span><span class="w"> </span><span class="py">version</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">120</span><span class="mf">.0</span><span class="err">'</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="err">//</span><span class="w"> </span><span class="py">Option</span><span class="w"> </span><span class="py">2</span><span class="p">:</span><span class="w"> </span><span class="nc">Flatten</span><span class="w"> </span><span class="py">commonly</span><span class="w"> </span><span class="py">queried</span><span class="w"> </span><span class="py">fields</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="p">(:</span><span class="nc">Event</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">1</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">name</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">PageView</span><span class="err">'</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">browser</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">Chrome</span><span class="err">'</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">os</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">Windows</span><span class="err">'</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">metadata</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="nc">version</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">120</span><span class="mf">.0</span><span class="err">'</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">})</span><span class="w">
</span></span></span></code></pre></div>
<h3 id="foreign-keys-to-relationships" class="position-relative d-flex align-items-center group">
<span>Foreign Keys to Relationships</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="foreign-keys-to-relationships"
aria-haspopup="dialog"
aria-label="Share link: Foreign Keys to Relationships">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="one-to-many-relationships" class="position-relative d-flex align-items-center group">
<span>One-to-Many Relationships</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="one-to-many-relationships"
aria-haspopup="dialog"
aria-label="Share link: One-to-Many Relationships">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>PostgreSQL</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">departments</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="nb">SERIAL</span><span class="w"> </span><span class="k">PRIMARY</span><span class="w"> </span><span class="k">KEY</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">255</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">employees</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="nb">SERIAL</span><span class="w"> </span><span class="k">PRIMARY</span><span class="w"> </span><span class="k">KEY</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">255</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">department_id</span><span class="w"> </span><span class="nb">INTEGER</span><span class="w"> </span><span class="k">REFERENCES</span><span class="w"> </span><span class="n">departments</span><span class="p">(</span><span class="n">id</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">);</span><span class="w">
</span></span></span></code></pre></div><p><strong>GQL</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">//</span><span class="w"> </span><span class="py">Create</span><span class="w"> </span><span class="py">nodes</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="p">(:</span><span class="nc">Department</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">1</span><span class="p">,</span><span class="w"> </span><span class="py">name</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">Engineering</span><span class="err">'</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="p">(:</span><span class="nc">Employee</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">1</span><span class="p">,</span><span class="w"> </span><span class="py">name</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">Alice</span><span class="err">'</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="err">//</span><span class="w"> </span><span class="py">Create</span><span class="w"> </span><span class="py">relationship</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">e</span><span class="p">:</span><span class="nc">Employee</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">1</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">d</span><span class="p">:</span><span class="nc">Department</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">1</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="p">(</span><span class="py">e</span><span class="p">)</span><span class="err">-</span><span class="p">[:</span><span class="nc">WORKS_IN</span><span class="p">]</span><span class="err">-></span><span class="p">(</span><span class="py">d</span><span class="p">)</span><span class="w">
</span></span></span></code></pre></div>
<h4 id="many-to-many-relationships-junction-tables" class="position-relative d-flex align-items-center group">
<span>Many-to-Many Relationships (Junction Tables)</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="many-to-many-relationships-junction-tables"
aria-haspopup="dialog"
aria-label="Share link: Many-to-Many Relationships (Junction Tables)">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>PostgreSQL</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="nb">SERIAL</span><span class="w"> </span><span class="k">PRIMARY</span><span class="w"> </span><span class="k">KEY</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">255</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">courses</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="nb">SERIAL</span><span class="w"> </span><span class="k">PRIMARY</span><span class="w"> </span><span class="k">KEY</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">255</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">enrollments</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">student_id</span><span class="w"> </span><span class="nb">INTEGER</span><span class="w"> </span><span class="k">REFERENCES</span><span class="w"> </span><span class="n">students</span><span class="p">(</span><span class="n">id</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">course_id</span><span class="w"> </span><span class="nb">INTEGER</span><span class="w"> </span><span class="k">REFERENCES</span><span class="w"> </span><span class="n">courses</span><span class="p">(</span><span class="n">id</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">enrolled_at</span><span class="w"> </span><span class="k">TIMESTAMP</span><span class="w"> </span><span class="k">DEFAULT</span><span class="w"> </span><span class="n">NOW</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">grade</span><span class="w"> </span><span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">2</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">PRIMARY</span><span class="w"> </span><span class="k">KEY</span><span class="w"> </span><span class="p">(</span><span class="n">student_id</span><span class="p">,</span><span class="w"> </span><span class="n">course_id</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">);</span><span class="w">
</span></span></span></code></pre></div><p><strong>GQL</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">//</span><span class="w"> </span><span class="py">Junction</span><span class="w"> </span><span class="py">table</span><span class="w"> </span><span class="py">becomes</span><span class="w"> </span><span class="py">relationship</span><span class="w"> </span><span class="py">with</span><span class="w"> </span><span class="py">properties</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="p">(:</span><span class="nc">Student</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">1</span><span class="p">,</span><span class="w"> </span><span class="py">name</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">Alice</span><span class="err">'</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="p">(:</span><span class="nc">Course</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">1</span><span class="p">,</span><span class="w"> </span><span class="py">name</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">Database</span><span class="w"> </span><span class="py">Systems</span><span class="err">'</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">s</span><span class="p">:</span><span class="nc">Student</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">1</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">c</span><span class="p">:</span><span class="nc">Course</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">1</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="p">(</span><span class="py">s</span><span class="p">)</span><span class="err">-</span><span class="p">[:</span><span class="nc">ENROLLED_IN</span><span class="w"> </span><span class="p">{</span><span class="py">enrolled_at</span><span class="p">:</span><span class="w"> </span><span class="nc">timestamp</span><span class="p">(),</span><span class="w"> </span><span class="py">grade</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">A</span><span class="err">'</span><span class="p">}]</span><span class="err">-></span><span class="p">(</span><span class="py">c</span><span class="p">)</span><span class="w">
</span></span></span></code></pre></div>
<h4 id="self-referential-relationships" class="position-relative d-flex align-items-center group">
<span>Self-Referential Relationships</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="self-referential-relationships"
aria-haspopup="dialog"
aria-label="Share link: Self-Referential Relationships">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>PostgreSQL</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">employees</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="nb">SERIAL</span><span class="w"> </span><span class="k">PRIMARY</span><span class="w"> </span><span class="k">KEY</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">255</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">manager_id</span><span class="w"> </span><span class="nb">INTEGER</span><span class="w"> </span><span class="k">REFERENCES</span><span class="w"> </span><span class="n">employees</span><span class="p">(</span><span class="n">id</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">);</span><span class="w">
</span></span></span></code></pre></div><p><strong>GQL</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="py">CREATE</span><span class="w"> </span><span class="p">(:</span><span class="nc">Employee</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">1</span><span class="p">,</span><span class="w"> </span><span class="py">name</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">CEO</span><span class="err">'</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="p">(:</span><span class="nc">Employee</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">2</span><span class="p">,</span><span class="w"> </span><span class="py">name</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">VP</span><span class="w"> </span><span class="py">Engineering</span><span class="err">'</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="p">(:</span><span class="nc">Employee</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">3</span><span class="p">,</span><span class="w"> </span><span class="py">name</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">Developer</span><span class="err">'</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">m</span><span class="p">:</span><span class="nc">Employee</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">1</span><span class="p">}),</span><span class="w"> </span><span class="p">(</span><span class="py">e</span><span class="p">:</span><span class="nc">Employee</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">2</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="p">(</span><span class="py">e</span><span class="p">)</span><span class="err">-</span><span class="p">[:</span><span class="nc">REPORTS_TO</span><span class="p">]</span><span class="err">-></span><span class="p">(</span><span class="py">m</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">m</span><span class="p">:</span><span class="nc">Employee</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">2</span><span class="p">}),</span><span class="w"> </span><span class="p">(</span><span class="py">e</span><span class="p">:</span><span class="nc">Employee</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">3</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="p">(</span><span class="py">e</span><span class="p">)</span><span class="err">-</span><span class="p">[:</span><span class="nc">REPORTS_TO</span><span class="p">]</span><span class="err">-></span><span class="p">(</span><span class="py">m</span><span class="p">)</span><span class="w">
</span></span></span></code></pre></div>
<h3 id="sql-to-gql-translation" class="position-relative d-flex align-items-center group">
<span>SQL to GQL Translation</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="sql-to-gql-translation"
aria-haspopup="dialog"
aria-label="Share link: SQL to GQL Translation">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="basic-queries" class="position-relative d-flex align-items-center group">
<span>Basic Queries</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="basic-queries"
aria-haspopup="dialog"
aria-label="Share link: Basic Queries">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>SELECT</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="c1">-- SQL
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">SELECT</span><span class="w"> </span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">email</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">customers</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">age</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="mi">25</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">--</span><span class="w"> </span><span class="py">GQL</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">c</span><span class="p">:</span><span class="nc">Customer</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">WHERE</span><span class="w"> </span><span class="py">c</span><span class="err">.</span><span class="py">age</span><span class="w"> </span><span class="err">></span><span class="w"> </span><span class="py">25</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">RETURN</span><span class="w"> </span><span class="py">c</span><span class="err">.</span><span class="py">name</span><span class="p">,</span><span class="w"> </span><span class="py">c</span><span class="err">.</span><span class="py">email</span><span class="w">
</span></span></span></code></pre></div><p><strong>INSERT</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="c1">-- SQL
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">INSERT</span><span class="w"> </span><span class="k">INTO</span><span class="w"> </span><span class="n">customers</span><span class="w"> </span><span class="p">(</span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">email</span><span class="p">,</span><span class="w"> </span><span class="n">age</span><span class="p">)</span><span class="w"> </span><span class="k">VALUES</span><span class="w"> </span><span class="p">(</span><span class="s1">'Alice'</span><span class="p">,</span><span class="w"> </span><span class="s1">'[email protected]'</span><span class="p">,</span><span class="w"> </span><span class="mi">30</span><span class="p">);</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">--</span><span class="w"> </span><span class="py">GQL</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="p">(:</span><span class="nc">Customer</span><span class="w"> </span><span class="p">{</span><span class="py">name</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">Alice</span><span class="err">'</span><span class="p">,</span><span class="w"> </span><span class="py">email</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">alice</span><span class="nd">@example</span><span class="err">.</span><span class="py">com</span><span class="err">'</span><span class="p">,</span><span class="w"> </span><span class="py">age</span><span class="p">:</span><span class="w"> </span><span class="nc">30</span><span class="p">})</span><span class="w">
</span></span></span></code></pre></div><p><strong>UPDATE</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="c1">-- SQL
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">UPDATE</span><span class="w"> </span><span class="n">customers</span><span class="w"> </span><span class="k">SET</span><span class="w"> </span><span class="n">age</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">31</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'Alice'</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">--</span><span class="w"> </span><span class="py">GQL</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">c</span><span class="p">:</span><span class="nc">Customer</span><span class="w"> </span><span class="p">{</span><span class="py">name</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">Alice</span><span class="err">'</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">SET</span><span class="w"> </span><span class="py">c</span><span class="err">.</span><span class="py">age</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">31</span><span class="w">
</span></span></span></code></pre></div><p><strong>DELETE</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="c1">-- SQL
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">DELETE</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">customers</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">--</span><span class="w"> </span><span class="py">GQL</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">c</span><span class="p">:</span><span class="nc">Customer</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">1</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">DELETE</span><span class="w"> </span><span class="py">c</span><span class="w">
</span></span></span></code></pre></div>
<h4 id="joins-to-pattern-matching" class="position-relative d-flex align-items-center group">
<span>Joins to Pattern Matching</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="joins-to-pattern-matching"
aria-haspopup="dialog"
aria-label="Share link: Joins to Pattern Matching">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>Inner Join</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="c1">-- SQL
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">SELECT</span><span class="w"> </span><span class="n">o</span><span class="p">.</span><span class="n">id</span><span class="p">,</span><span class="w"> </span><span class="k">c</span><span class="p">.</span><span class="n">name</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">orders</span><span class="w"> </span><span class="n">o</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">INNER</span><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="n">customers</span><span class="w"> </span><span class="k">c</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="n">o</span><span class="p">.</span><span class="n">customer_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">c</span><span class="p">.</span><span class="n">id</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">--</span><span class="w"> </span><span class="py">GQL</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">c</span><span class="p">:</span><span class="nc">Customer</span><span class="p">)</span><span class="err">-</span><span class="p">[:</span><span class="nc">PLACED</span><span class="p">]</span><span class="err">-></span><span class="p">(</span><span class="py">o</span><span class="p">:</span><span class="nc">Order</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">RETURN</span><span class="w"> </span><span class="py">o</span><span class="err">.</span><span class="py">id</span><span class="p">,</span><span class="w"> </span><span class="py">c</span><span class="err">.</span><span class="py">name</span><span class="w">
</span></span></span></code></pre></div><p><strong>Left Join</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="c1">-- SQL
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">SELECT</span><span class="w"> </span><span class="k">c</span><span class="p">.</span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">o</span><span class="p">.</span><span class="n">id</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">customers</span><span class="w"> </span><span class="k">c</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">LEFT</span><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="n">orders</span><span class="w"> </span><span class="n">o</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="k">c</span><span class="p">.</span><span class="n">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">o</span><span class="p">.</span><span class="n">customer_id</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">--</span><span class="w"> </span><span class="py">GQL</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">c</span><span class="p">:</span><span class="nc">Customer</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">OPTIONAL</span><span class="w"> </span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">c</span><span class="p">)</span><span class="err">-</span><span class="p">[:</span><span class="nc">PLACED</span><span class="p">]</span><span class="err">-></span><span class="p">(</span><span class="py">o</span><span class="p">:</span><span class="nc">Order</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">RETURN</span><span class="w"> </span><span class="py">c</span><span class="err">.</span><span class="py">name</span><span class="p">,</span><span class="w"> </span><span class="py">o</span><span class="err">.</span><span class="py">id</span><span class="w">
</span></span></span></code></pre></div><p><strong>Multiple Joins</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="c1">-- SQL
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">SELECT</span><span class="w"> </span><span class="k">c</span><span class="p">.</span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">p</span><span class="p">.</span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">oi</span><span class="p">.</span><span class="n">quantity</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">customers</span><span class="w"> </span><span class="k">c</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">JOIN</span><span class="w"> </span><span class="n">orders</span><span class="w"> </span><span class="n">o</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="k">c</span><span class="p">.</span><span class="n">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">o</span><span class="p">.</span><span class="n">customer_id</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">JOIN</span><span class="w"> </span><span class="n">order_items</span><span class="w"> </span><span class="n">oi</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="n">o</span><span class="p">.</span><span class="n">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">oi</span><span class="p">.</span><span class="n">order_id</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">JOIN</span><span class="w"> </span><span class="n">products</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="n">oi</span><span class="p">.</span><span class="n">product_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">p</span><span class="p">.</span><span class="n">id</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">--</span><span class="w"> </span><span class="py">GQL</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">c</span><span class="p">:</span><span class="nc">Customer</span><span class="p">)</span><span class="err">-</span><span class="p">[:</span><span class="nc">PLACED</span><span class="p">]</span><span class="err">-></span><span class="p">(</span><span class="py">o</span><span class="p">:</span><span class="nc">Order</span><span class="p">)</span><span class="err">-</span><span class="p">[</span><span class="py">item</span><span class="p">:</span><span class="nc">CONTAINS</span><span class="p">]</span><span class="err">-></span><span class="p">(</span><span class="py">p</span><span class="p">:</span><span class="nc">Product</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">RETURN</span><span class="w"> </span><span class="py">c</span><span class="err">.</span><span class="py">name</span><span class="p">,</span><span class="w"> </span><span class="py">p</span><span class="err">.</span><span class="py">name</span><span class="p">,</span><span class="w"> </span><span class="py">item</span><span class="err">.</span><span class="py">quantity</span><span class="w">
</span></span></span></code></pre></div>
<h4 id="subqueries" class="position-relative d-flex align-items-center group">
<span>Subqueries</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="subqueries"
aria-haspopup="dialog"
aria-label="Share link: Subqueries">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>Correlated Subquery</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="c1">-- SQL
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">SELECT</span><span class="w"> </span><span class="k">c</span><span class="p">.</span><span class="n">name</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">(</span><span class="k">SELECT</span><span class="w"> </span><span class="k">COUNT</span><span class="p">(</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">orders</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">customer_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">c</span><span class="p">.</span><span class="n">id</span><span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">order_count</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">customers</span><span class="w"> </span><span class="k">c</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">--</span><span class="w"> </span><span class="py">GQL</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">c</span><span class="p">:</span><span class="nc">Customer</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">OPTIONAL</span><span class="w"> </span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">c</span><span class="p">)</span><span class="err">-</span><span class="p">[:</span><span class="nc">PLACED</span><span class="p">]</span><span class="err">-></span><span class="p">(</span><span class="py">o</span><span class="p">:</span><span class="nc">Order</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">RETURN</span><span class="w"> </span><span class="py">c</span><span class="err">.</span><span class="py">name</span><span class="p">,</span><span class="w"> </span><span class="py">count</span><span class="p">(</span><span class="py">o</span><span class="p">)</span><span class="w"> </span><span class="py">AS</span><span class="w"> </span><span class="py">order_count</span><span class="w">
</span></span></span></code></pre></div><p><strong>EXISTS Subquery</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="c1">-- SQL
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">customers</span><span class="w"> </span><span class="k">c</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">WHERE</span><span class="w"> </span><span class="k">EXISTS</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">SELECT</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">orders</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">customer_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">c</span><span class="p">.</span><span class="n">id</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">);</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">--</span><span class="w"> </span><span class="py">GQL</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">c</span><span class="p">:</span><span class="nc">Customer</span><span class="p">)</span><span class="err">-</span><span class="p">[:</span><span class="nc">PLACED</span><span class="p">]</span><span class="err">-></span><span class="p">(:</span><span class="nc">Order</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">RETURN</span><span class="w"> </span><span class="py">DISTINCT</span><span class="w"> </span><span class="py">c</span><span class="w">
</span></span></span></code></pre></div>
<h4 id="aggregations" class="position-relative d-flex align-items-center group">
<span>Aggregations</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="aggregations"
aria-haspopup="dialog"
aria-label="Share link: Aggregations">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>GROUP BY</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="c1">-- SQL
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">SELECT</span><span class="w"> </span><span class="n">category_id</span><span class="p">,</span><span class="w"> </span><span class="k">COUNT</span><span class="p">(</span><span class="o">*</span><span class="p">),</span><span class="w"> </span><span class="k">AVG</span><span class="p">(</span><span class="n">price</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">products</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">GROUP</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">category_id</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">--</span><span class="w"> </span><span class="py">GQL</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">p</span><span class="p">:</span><span class="nc">Product</span><span class="p">)</span><span class="err">-</span><span class="p">[:</span><span class="nc">IN_CATEGORY</span><span class="p">]</span><span class="err">-></span><span class="p">(</span><span class="py">c</span><span class="p">:</span><span class="nc">Category</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">RETURN</span><span class="w"> </span><span class="py">c</span><span class="err">.</span><span class="py">id</span><span class="p">,</span><span class="w"> </span><span class="py">count</span><span class="p">(</span><span class="py">p</span><span class="p">),</span><span class="w"> </span><span class="py">avg</span><span class="p">(</span><span class="py">p</span><span class="err">.</span><span class="py">price</span><span class="p">)</span><span class="w">
</span></span></span></code></pre></div><p><strong>HAVING</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="c1">-- SQL
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">SELECT</span><span class="w"> </span><span class="n">customer_id</span><span class="p">,</span><span class="w"> </span><span class="k">COUNT</span><span class="p">(</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">order_count</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">orders</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">GROUP</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">customer_id</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">HAVING</span><span class="w"> </span><span class="k">COUNT</span><span class="p">(</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="mi">5</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">--</span><span class="w"> </span><span class="py">GQL</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">c</span><span class="p">:</span><span class="nc">Customer</span><span class="p">)</span><span class="err">-</span><span class="p">[:</span><span class="nc">PLACED</span><span class="p">]</span><span class="err">-></span><span class="p">(</span><span class="py">o</span><span class="p">:</span><span class="nc">Order</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">WITH</span><span class="w"> </span><span class="py">c</span><span class="p">,</span><span class="w"> </span><span class="py">count</span><span class="p">(</span><span class="py">o</span><span class="p">)</span><span class="w"> </span><span class="py">AS</span><span class="w"> </span><span class="py">order_count</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">WHERE</span><span class="w"> </span><span class="py">order_count</span><span class="w"> </span><span class="err">></span><span class="w"> </span><span class="py">5</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">RETURN</span><span class="w"> </span><span class="py">c</span><span class="err">.</span><span class="py">id</span><span class="p">,</span><span class="w"> </span><span class="py">order_count</span><span class="w">
</span></span></span></code></pre></div>
<h4 id="window-functions" class="position-relative d-flex align-items-center group">
<span>Window Functions</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="window-functions"
aria-haspopup="dialog"
aria-label="Share link: Window Functions">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>ROW_NUMBER</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="c1">-- SQL
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">SELECT</span><span class="w"> </span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">price</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">ROW_NUMBER</span><span class="p">()</span><span class="w"> </span><span class="n">OVER</span><span class="w"> </span><span class="p">(</span><span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">price</span><span class="w"> </span><span class="k">DESC</span><span class="p">)</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">rank</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">products</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">--</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span><span class="p">(</span><span class="py">using</span><span class="w"> </span><span class="py">collect</span><span class="w"> </span><span class="py">and</span><span class="w"> </span><span class="py">unwind</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">p</span><span class="p">:</span><span class="nc">Product</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">WITH</span><span class="w"> </span><span class="py">p</span><span class="w"> </span><span class="py">ORDER</span><span class="w"> </span><span class="py">BY</span><span class="w"> </span><span class="py">p</span><span class="err">.</span><span class="py">price</span><span class="w"> </span><span class="py">DESC</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">WITH</span><span class="w"> </span><span class="py">collect</span><span class="p">(</span><span class="py">p</span><span class="p">)</span><span class="w"> </span><span class="py">AS</span><span class="w"> </span><span class="py">products</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">UNWIND</span><span class="w"> </span><span class="py">range</span><span class="p">(</span><span class="py">0</span><span class="p">,</span><span class="w"> </span><span class="py">size</span><span class="p">(</span><span class="py">products</span><span class="p">)</span><span class="err">-</span><span class="py">1</span><span class="p">)</span><span class="w"> </span><span class="py">AS</span><span class="w"> </span><span class="py">idx</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">RETURN</span><span class="w"> </span><span class="py">products</span><span class="p">[</span><span class="py">idx</span><span class="p">]</span><span class="err">.</span><span class="py">name</span><span class="p">,</span><span class="w"> </span><span class="py">products</span><span class="p">[</span><span class="py">idx</span><span class="p">]</span><span class="err">.</span><span class="py">price</span><span class="p">,</span><span class="w"> </span><span class="py">idx</span><span class="w"> </span><span class="err">+</span><span class="w"> </span><span class="py">1</span><span class="w"> </span><span class="py">AS</span><span class="w"> </span><span class="py">rank</span><span class="w">
</span></span></span></code></pre></div>
<h4 id="common-table-expressions-ctes" class="position-relative d-flex align-items-center group">
<span>Common Table Expressions (CTEs)</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="common-table-expressions-ctes"
aria-haspopup="dialog"
aria-label="Share link: Common Table Expressions (CTEs)">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="c1">-- SQL
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">WITH</span><span class="w"> </span><span class="n">high_value_customers</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">SELECT</span><span class="w"> </span><span class="n">customer_id</span><span class="p">,</span><span class="w"> </span><span class="k">SUM</span><span class="p">(</span><span class="n">total</span><span class="p">)</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">total_spent</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">orders</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">GROUP</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">customer_id</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">HAVING</span><span class="w"> </span><span class="k">SUM</span><span class="p">(</span><span class="n">total</span><span class="p">)</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="mi">1000</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">SELECT</span><span class="w"> </span><span class="k">c</span><span class="p">.</span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">hvc</span><span class="p">.</span><span class="n">total_spent</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">customers</span><span class="w"> </span><span class="k">c</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">JOIN</span><span class="w"> </span><span class="n">high_value_customers</span><span class="w"> </span><span class="n">hvc</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="k">c</span><span class="p">.</span><span class="n">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">hvc</span><span class="p">.</span><span class="n">customer_id</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">--</span><span class="w"> </span><span class="py">GQL</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">c</span><span class="p">:</span><span class="nc">Customer</span><span class="p">)</span><span class="err">-</span><span class="p">[:</span><span class="nc">PLACED</span><span class="p">]</span><span class="err">-></span><span class="p">(</span><span class="py">o</span><span class="p">:</span><span class="nc">Order</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">WITH</span><span class="w"> </span><span class="py">c</span><span class="p">,</span><span class="w"> </span><span class="py">sum</span><span class="p">(</span><span class="py">o</span><span class="err">.</span><span class="py">total</span><span class="p">)</span><span class="w"> </span><span class="py">AS</span><span class="w"> </span><span class="py">total_spent</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">WHERE</span><span class="w"> </span><span class="py">total_spent</span><span class="w"> </span><span class="err">></span><span class="w"> </span><span class="py">1000</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">RETURN</span><span class="w"> </span><span class="py">c</span><span class="err">.</span><span class="py">name</span><span class="p">,</span><span class="w"> </span><span class="py">total_spent</span><span class="w">
</span></span></span></code></pre></div>
<h4 id="recursive-queries" class="position-relative d-flex align-items-center group">
<span>Recursive Queries</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="recursive-queries"
aria-haspopup="dialog"
aria-label="Share link: Recursive Queries">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>PostgreSQL Recursive CTE</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="c1">-- SQL: Find all subordinates
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">WITH</span><span class="w"> </span><span class="k">RECURSIVE</span><span class="w"> </span><span class="n">subordinates</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">SELECT</span><span class="w"> </span><span class="n">id</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">manager_id</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">employees</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">UNION</span><span class="w"> </span><span class="k">ALL</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">SELECT</span><span class="w"> </span><span class="n">e</span><span class="p">.</span><span class="n">id</span><span class="p">,</span><span class="w"> </span><span class="n">e</span><span class="p">.</span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">e</span><span class="p">.</span><span class="n">manager_id</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">employees</span><span class="w"> </span><span class="n">e</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="n">subordinates</span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="n">e</span><span class="p">.</span><span class="n">manager_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">s</span><span class="p">.</span><span class="n">id</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">subordinates</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><p><strong>GQL Variable-Length Path</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">--</span><span class="w"> </span><span class="py">GQL</span><span class="p">:</span><span class="w"> </span><span class="nc">Much</span><span class="w"> </span><span class="py">simpler</span><span class="p">!</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">manager</span><span class="p">:</span><span class="nc">Employee</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">1</span><span class="p">})</span><span class="err"><-</span><span class="p">[:</span><span class="nc">REPORTS_TO</span><span class="err">*</span><span class="p">]</span><span class="err">-</span><span class="p">(</span><span class="py">subordinate</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">RETURN</span><span class="w"> </span><span class="py">subordinate</span><span class="err">.</span><span class="py">id</span><span class="p">,</span><span class="w"> </span><span class="py">subordinate</span><span class="err">.</span><span class="py">name</span><span class="w">
</span></span></span></code></pre></div>
<h3 id="etl-pipeline-setup" class="position-relative d-flex align-items-center group">
<span>ETL Pipeline Setup</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="etl-pipeline-setup"
aria-haspopup="dialog"
aria-label="Share link: ETL Pipeline Setup">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="architecture-overview" class="position-relative d-flex align-items-center group">
<span>Architecture Overview</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="architecture-overview"
aria-haspopup="dialog"
aria-label="Share link: Architecture Overview">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">┌─────────────┐ ┌─────────────┐ ┌─────────────┐
</span></span><span class="line"><span class="cl">│ PostgreSQL │────▶│ ETL Job │────▶│ Geode │
</span></span><span class="line"><span class="cl">└─────────────┘ └─────────────┘ └─────────────┘
</span></span><span class="line"><span class="cl"> │ │
</span></span><span class="line"><span class="cl"> │ ┌──────┴──────┐
</span></span><span class="line"><span class="cl"> │ │ │
</span></span><span class="line"><span class="cl"> ▼ ▼ ▼
</span></span><span class="line"><span class="cl"> ┌─────────┐ ┌─────────┐ ┌─────────┐
</span></span><span class="line"><span class="cl"> │ Extract │ │Transform│ │ Load │
</span></span><span class="line"><span class="cl"> └─────────┘ └─────────┘ └─────────┘
</span></span></code></pre></div>
<h4 id="python-etl-script" class="position-relative d-flex align-items-center group">
<span>Python ETL Script</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="python-etl-script"
aria-haspopup="dialog"
aria-label="Share link: Python ETL Script">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">asyncio</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">psycopg</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">geode_client</span> <span class="kn">import</span> <span class="n">Client</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Configuration</span>
</span></span><span class="line"><span class="cl"><span class="n">PG_CONFIG</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"host"</span><span class="p">:</span> <span class="s2">"localhost"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"port"</span><span class="p">:</span> <span class="mi">5432</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"user"</span><span class="p">:</span> <span class="s2">"postgres"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"password"</span><span class="p">:</span> <span class="s2">"password"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"dbname"</span><span class="p">:</span> <span class="s2">"ecommerce"</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">GEODE_CONFIG</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"host"</span><span class="p">:</span> <span class="s2">"localhost"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"port"</span><span class="p">:</span> <span class="mi">3141</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"skip_verify"</span><span class="p">:</span> <span class="kc">True</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">PostgresToGeodeETL</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">pg_conn</span> <span class="o">=</span> <span class="kc">None</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">geode_client</span> <span class="o">=</span> <span class="kc">None</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">def</span> <span class="nf">connect</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># Connect to PostgreSQL</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">pg_conn</span> <span class="o">=</span> <span class="k">await</span> <span class="n">psycopg</span><span class="o">.</span><span class="n">AsyncConnection</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="o">**</span><span class="n">PG_CONFIG</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">autocommit</span><span class="o">=</span><span class="kc">True</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Connect to Geode</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">geode_client</span> <span class="o">=</span> <span class="n">Client</span><span class="p">(</span><span class="o">**</span><span class="n">GEODE_CONFIG</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">def</span> <span class="nf">extract_table</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">table_name</span><span class="p">,</span> <span class="n">batch_size</span><span class="o">=</span><span class="mi">1000</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Extract data from PostgreSQL table in batches."""</span>
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">pg_conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span> <span class="k">as</span> <span class="n">cur</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="sa">f</span><span class="s2">"SELECT COUNT(*) FROM </span><span class="si">{</span><span class="n">table_name</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">total</span> <span class="o">=</span> <span class="p">(</span><span class="k">await</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchone</span><span class="p">())[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">offset</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">total</span><span class="p">,</span> <span class="n">batch_size</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="sa">f</span><span class="s2">"SELECT * FROM </span><span class="si">{</span><span class="n">table_name</span><span class="si">}</span><span class="s2"> ORDER BY id LIMIT %s OFFSET %s"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">(</span><span class="n">batch_size</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">columns</span> <span class="o">=</span> <span class="p">[</span><span class="n">desc</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="n">desc</span> <span class="ow">in</span> <span class="n">cur</span><span class="o">.</span><span class="n">description</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="n">rows</span> <span class="o">=</span> <span class="k">await</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">rows</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">yield</span> <span class="nb">dict</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">columns</span><span class="p">,</span> <span class="n">row</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">def</span> <span class="nf">load_nodes</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">label</span><span class="p">,</span> <span class="n">data_generator</span><span class="p">,</span> <span class="n">id_field</span><span class="o">=</span><span class="s1">'id'</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Load nodes into Geode."""</span>
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">geode_client</span><span class="o">.</span><span class="n">connection</span><span class="p">()</span> <span class="k">as</span> <span class="n">conn</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">count</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">begin</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">data_generator</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># Convert types as needed</span>
</span></span><span class="line"><span class="cl"> <span class="n">props</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">transform_properties</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="sa">f</span><span class="s2">"CREATE (n:</span><span class="si">{</span><span class="n">label</span><span class="si">}</span><span class="s2"> $props)"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s2">"props"</span><span class="p">:</span> <span class="n">props</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">count</span> <span class="o">+=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Commit in batches</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">count</span> <span class="o">%</span> <span class="mi">1000</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">begin</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Loaded </span><span class="si">{</span><span class="n">count</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">label</span><span class="si">}</span><span class="s2"> nodes..."</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Total: </span><span class="si">{</span><span class="n">count</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">label</span><span class="si">}</span><span class="s2"> nodes loaded"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">def</span> <span class="nf">load_relationships</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">rel_type</span><span class="p">,</span> <span class="n">from_label</span><span class="p">,</span> <span class="n">to_label</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">from_field</span><span class="p">,</span> <span class="n">to_field</span><span class="p">,</span> <span class="n">data_generator</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Load relationships into Geode."""</span>
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">geode_client</span><span class="o">.</span><span class="n">connection</span><span class="p">()</span> <span class="k">as</span> <span class="n">conn</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">count</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">begin</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">data_generator</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">props</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="n">v</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">row</span><span class="o">.</span><span class="n">items</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">k</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="n">from_field</span><span class="p">,</span> <span class="n">to_field</span><span class="p">]}</span>
</span></span><span class="line"><span class="cl"> <span class="n">props</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">transform_properties</span><span class="p">(</span><span class="n">props</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="sa">f</span><span class="s2">"""
</span></span></span><span class="line"><span class="cl"><span class="s2"> MATCH (a:</span><span class="si">{</span><span class="n">from_label</span><span class="si">}</span><span class="s2"> </span><span class="se">{{</span><span class="s2">id: $from_id</span><span class="se">}}</span><span class="s2">)
</span></span></span><span class="line"><span class="cl"><span class="s2"> MATCH (b:</span><span class="si">{</span><span class="n">to_label</span><span class="si">}</span><span class="s2"> </span><span class="se">{{</span><span class="s2">id: $to_id</span><span class="se">}}</span><span class="s2">)
</span></span></span><span class="line"><span class="cl"><span class="s2"> CREATE (a)-[:</span><span class="si">{</span><span class="n">rel_type</span><span class="si">}</span><span class="s2"> $props]->(b)
</span></span></span><span class="line"><span class="cl"><span class="s2"> """</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"from_id"</span><span class="p">:</span> <span class="n">row</span><span class="p">[</span><span class="n">from_field</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"to_id"</span><span class="p">:</span> <span class="n">row</span><span class="p">[</span><span class="n">to_field</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"props"</span><span class="p">:</span> <span class="n">props</span>
</span></span><span class="line"><span class="cl"> <span class="p">})</span>
</span></span><span class="line"><span class="cl"> <span class="n">count</span> <span class="o">+=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">count</span> <span class="o">%</span> <span class="mi">1000</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">begin</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Loaded </span><span class="si">{</span><span class="n">count</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">rel_type</span><span class="si">}</span><span class="s2"> relationships..."</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Total: </span><span class="si">{</span><span class="n">count</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">rel_type</span><span class="si">}</span><span class="s2"> relationships loaded"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="nf">transform_properties</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">row</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Transform PostgreSQL types to Geode-compatible types."""</span>
</span></span><span class="line"><span class="cl"> <span class="n">result</span> <span class="o">=</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">row</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">value</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">continue</span> <span class="c1"># Skip null values</span>
</span></span><span class="line"><span class="cl"> <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">datetime</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="n">result</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span><span class="o">.</span><span class="n">isoformat</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">Decimal</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="n">result</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="p">(</span><span class="nb">list</span><span class="p">,</span> <span class="nb">dict</span><span class="p">)):</span>
</span></span><span class="line"><span class="cl"> <span class="n">result</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span> <span class="c1"># Lists and maps are supported</span>
</span></span><span class="line"><span class="cl"> <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">result</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">result</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">def</span> <span class="nf">run_migration</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Run the complete migration."""</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">connect</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Step 1: Create indexes for efficient relationship creation</span>
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">geode_client</span><span class="o">.</span><span class="n">connection</span><span class="p">()</span> <span class="k">as</span> <span class="n">conn</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">"CREATE INDEX customer_id ON :Customer(id)"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">"CREATE INDEX product_id ON :Product(id)"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">"CREATE INDEX category_id ON :Category(id)"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">"CREATE INDEX order_id ON :Order(id)"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Step 2: Load nodes</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">=== Loading Nodes ==="</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">load_nodes</span><span class="p">(</span><span class="s1">'Customer'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">extract_table</span><span class="p">(</span><span class="s1">'customers'</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">load_nodes</span><span class="p">(</span><span class="s1">'Category'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">extract_table</span><span class="p">(</span><span class="s1">'categories'</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">load_nodes</span><span class="p">(</span><span class="s1">'Product'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">extract_table</span><span class="p">(</span><span class="s1">'products'</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">load_nodes</span><span class="p">(</span><span class="s1">'Order'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">extract_table</span><span class="p">(</span><span class="s1">'orders'</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Step 3: Load relationships</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">=== Loading Relationships ==="</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Product -> Category</span>
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">pg_conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span> <span class="k">as</span> <span class="n">cur</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">"""
</span></span></span><span class="line"><span class="cl"><span class="s2"> SELECT id as product_id, category_id
</span></span></span><span class="line"><span class="cl"><span class="s2"> FROM products
</span></span></span><span class="line"><span class="cl"><span class="s2"> WHERE category_id IS NOT NULL
</span></span></span><span class="line"><span class="cl"><span class="s2"> """</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">columns</span> <span class="o">=</span> <span class="p">[</span><span class="n">desc</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="n">desc</span> <span class="ow">in</span> <span class="n">cur</span><span class="o">.</span><span class="n">description</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="n">rows</span> <span class="o">=</span> <span class="k">await</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">def</span> <span class="nf">product_category_gen</span><span class="p">():</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">rows</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">yield</span> <span class="nb">dict</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">columns</span><span class="p">,</span> <span class="n">row</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">load_relationships</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'IN_CATEGORY'</span><span class="p">,</span> <span class="s1">'Product'</span><span class="p">,</span> <span class="s1">'Category'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'product_id'</span><span class="p">,</span> <span class="s1">'category_id'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">product_category_gen</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Category -> Parent Category</span>
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">pg_conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span> <span class="k">as</span> <span class="n">cur</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">"""
</span></span></span><span class="line"><span class="cl"><span class="s2"> SELECT id as child_id, parent_id
</span></span></span><span class="line"><span class="cl"><span class="s2"> FROM categories
</span></span></span><span class="line"><span class="cl"><span class="s2"> WHERE parent_id IS NOT NULL
</span></span></span><span class="line"><span class="cl"><span class="s2"> """</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">columns</span> <span class="o">=</span> <span class="p">[</span><span class="n">desc</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="n">desc</span> <span class="ow">in</span> <span class="n">cur</span><span class="o">.</span><span class="n">description</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="n">rows</span> <span class="o">=</span> <span class="k">await</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">def</span> <span class="nf">category_parent_gen</span><span class="p">():</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">rows</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">yield</span> <span class="nb">dict</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">columns</span><span class="p">,</span> <span class="n">row</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">load_relationships</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'PARENT'</span><span class="p">,</span> <span class="s1">'Category'</span><span class="p">,</span> <span class="s1">'Category'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'child_id'</span><span class="p">,</span> <span class="s1">'parent_id'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">category_parent_gen</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Customer -> Order</span>
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">pg_conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span> <span class="k">as</span> <span class="n">cur</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">"""
</span></span></span><span class="line"><span class="cl"><span class="s2"> SELECT id as order_id, customer_id
</span></span></span><span class="line"><span class="cl"><span class="s2"> FROM orders
</span></span></span><span class="line"><span class="cl"><span class="s2"> """</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">columns</span> <span class="o">=</span> <span class="p">[</span><span class="n">desc</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="n">desc</span> <span class="ow">in</span> <span class="n">cur</span><span class="o">.</span><span class="n">description</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="n">rows</span> <span class="o">=</span> <span class="k">await</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">def</span> <span class="nf">customer_order_gen</span><span class="p">():</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">rows</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">yield</span> <span class="nb">dict</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">columns</span><span class="p">,</span> <span class="n">row</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">load_relationships</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'PLACED'</span><span class="p">,</span> <span class="s1">'Customer'</span><span class="p">,</span> <span class="s1">'Order'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'customer_id'</span><span class="p">,</span> <span class="s1">'order_id'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">customer_order_gen</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Order -> Product (from order_items)</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">load_relationships</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'CONTAINS'</span><span class="p">,</span> <span class="s1">'Order'</span><span class="p">,</span> <span class="s1">'Product'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'order_id'</span><span class="p">,</span> <span class="s1">'product_id'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">extract_table</span><span class="p">(</span><span class="s1">'order_items'</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Customer -> Product (reviews)</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">load_relationships</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'REVIEWED'</span><span class="p">,</span> <span class="s1">'Customer'</span><span class="p">,</span> <span class="s1">'Product'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'customer_id'</span><span class="p">,</span> <span class="s1">'product_id'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">extract_table</span><span class="p">(</span><span class="s1">'reviews'</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">=== Migration Complete ==="</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Run migration</span>
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
</span></span><span class="line"><span class="cl"> <span class="n">etl</span> <span class="o">=</span> <span class="n">PostgresToGeodeETL</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">etl</span><span class="o">.</span><span class="n">run_migration</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">main</span><span class="p">())</span>
</span></span></code></pre></div>
<h4 id="go-etl-script" class="position-relative d-flex align-items-center group">
<span>Go ETL Script</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="go-etl-script"
aria-haspopup="dialog"
aria-label="Share link: Go ETL Script">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s">"context"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"database/sql"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"fmt"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"log"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">_</span> <span class="s">"github.com/lib/pq"</span>
</span></span><span class="line"><span class="cl"> <span class="nx">_</span> <span class="s">"geodedb.com/geode"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">ETL</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">pg</span> <span class="o">*</span><span class="nx">sql</span><span class="p">.</span><span class="nx">DB</span>
</span></span><span class="line"><span class="cl"> <span class="nx">geode</span> <span class="o">*</span><span class="nx">sql</span><span class="p">.</span><span class="nx">DB</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">NewETL</span><span class="p">(</span><span class="nx">pgConn</span><span class="p">,</span> <span class="nx">geodeConn</span> <span class="kt">string</span><span class="p">)</span> <span class="p">(</span><span class="o">*</span><span class="nx">ETL</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">pg</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">sql</span><span class="p">.</span><span class="nf">Open</span><span class="p">(</span><span class="s">"postgres"</span><span class="p">,</span> <span class="nx">pgConn</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">nil</span><span class="p">,</span> <span class="nx">err</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">geode</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">sql</span><span class="p">.</span><span class="nf">Open</span><span class="p">(</span><span class="s">"geode"</span><span class="p">,</span> <span class="nx">geodeConn</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">nil</span><span class="p">,</span> <span class="nx">err</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="o">&</span><span class="nx">ETL</span><span class="p">{</span><span class="nx">pg</span><span class="p">:</span> <span class="nx">pg</span><span class="p">,</span> <span class="nx">geode</span><span class="p">:</span> <span class="nx">geode</span><span class="p">},</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">e</span> <span class="o">*</span><span class="nx">ETL</span><span class="p">)</span> <span class="nf">MigrateTable</span><span class="p">(</span><span class="nx">ctx</span> <span class="nx">context</span><span class="p">.</span><span class="nx">Context</span><span class="p">,</span> <span class="nx">table</span><span class="p">,</span> <span class="nx">label</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// Count rows
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="kd">var</span> <span class="nx">count</span> <span class="kt">int</span>
</span></span><span class="line"><span class="cl"> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">e</span><span class="p">.</span><span class="nx">pg</span><span class="p">.</span><span class="nf">QueryRowContext</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Sprintf</span><span class="p">(</span><span class="s">"SELECT COUNT(*) FROM %s"</span><span class="p">,</span> <span class="nx">table</span><span class="p">)).</span><span class="nf">Scan</span><span class="p">(</span><span class="o">&</span><span class="nx">count</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">err</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"Migrating %d rows from %s to %s"</span><span class="p">,</span> <span class="nx">count</span><span class="p">,</span> <span class="nx">table</span><span class="p">,</span> <span class="nx">label</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1">// Query source data
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">rows</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">e</span><span class="p">.</span><span class="nx">pg</span><span class="p">.</span><span class="nf">QueryContext</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Sprintf</span><span class="p">(</span><span class="s">"SELECT * FROM %s"</span><span class="p">,</span> <span class="nx">table</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">err</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">defer</span> <span class="nx">rows</span><span class="p">.</span><span class="nf">Close</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">columns</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">rows</span><span class="p">.</span><span class="nf">Columns</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">err</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1">// Begin transaction
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">tx</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">e</span><span class="p">.</span><span class="nx">geode</span><span class="p">.</span><span class="nf">BeginTx</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span> <span class="kc">nil</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">err</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">migrated</span> <span class="o">:=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">rows</span><span class="p">.</span><span class="nf">Next</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// Scan row
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">values</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kd">interface</span><span class="p">{},</span> <span class="nb">len</span><span class="p">(</span><span class="nx">columns</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"> <span class="nx">valuePtrs</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kd">interface</span><span class="p">{},</span> <span class="nb">len</span><span class="p">(</span><span class="nx">columns</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">i</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">values</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">valuePtrs</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="p">=</span> <span class="o">&</span><span class="nx">values</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">rows</span><span class="p">.</span><span class="nf">Scan</span><span class="p">(</span><span class="nx">valuePtrs</span><span class="o">...</span><span class="p">);</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">err</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1">// Build property map
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">props</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kd">interface</span><span class="p">{})</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">i</span><span class="p">,</span> <span class="nx">col</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">columns</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">values</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">props</span><span class="p">[</span><span class="nx">col</span><span class="p">]</span> <span class="p">=</span> <span class="nx">values</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1">// Insert into Geode
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">_</span><span class="p">,</span> <span class="nx">err</span> <span class="p">=</span> <span class="nx">tx</span><span class="p">.</span><span class="nf">ExecContext</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Sprintf</span><span class="p">(</span><span class="s">"CREATE (n:%s $props)"</span><span class="p">,</span> <span class="nx">label</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="nx">props</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">tx</span><span class="p">.</span><span class="nf">Rollback</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">err</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">migrated</span><span class="o">++</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">migrated</span><span class="o">%</span><span class="mi">1000</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"Migrated %d/%d rows"</span><span class="p">,</span> <span class="nx">migrated</span><span class="p">,</span> <span class="nx">count</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">tx</span><span class="p">.</span><span class="nf">Commit</span><span class="p">();</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">err</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"Completed: %d rows migrated"</span><span class="p">,</span> <span class="nx">migrated</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">etl</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nf">NewETL</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s">"postgres://user:pass@localhost/db?sslmode=disable"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s">"localhost:3141"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Fatal</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">ctx</span> <span class="o">:=</span> <span class="nx">context</span><span class="p">.</span><span class="nf">Background</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1">// Migrate tables
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">tables</span> <span class="o">:=</span> <span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">string</span><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="s">"customers"</span><span class="p">:</span> <span class="s">"Customer"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s">"products"</span><span class="p">:</span> <span class="s">"Product"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s">"categories"</span><span class="p">:</span> <span class="s">"Category"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s">"orders"</span><span class="p">:</span> <span class="s">"Order"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">table</span><span class="p">,</span> <span class="nx">label</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">tables</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">etl</span><span class="p">.</span><span class="nf">MigrateTable</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span> <span class="nx">table</span><span class="p">,</span> <span class="nx">label</span><span class="p">);</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Fatalf</span><span class="p">(</span><span class="s">"Failed to migrate %s: %v"</span><span class="p">,</span> <span class="nx">table</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">"Migration complete!"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div>
<h3 id="incremental-migration" class="position-relative d-flex align-items-center group">
<span>Incremental Migration</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="incremental-migration"
aria-haspopup="dialog"
aria-label="Share link: Incremental Migration">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="change-data-capture-cdc-setup" class="position-relative d-flex align-items-center group">
<span>Change Data Capture (CDC) Setup</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="change-data-capture-cdc-setup"
aria-haspopup="dialog"
aria-label="Share link: Change Data Capture (CDC) Setup">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Use PostgreSQL logical replication to capture changes:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="c1">-- Enable logical replication in postgresql.conf
</span></span></span><span class="line"><span class="cl"><span class="c1">-- wal_level = logical
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">-- Create replication slot
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">SELECT</span><span class="w"> </span><span class="n">pg_create_logical_replication_slot</span><span class="p">(</span><span class="s1">'geode_slot'</span><span class="p">,</span><span class="w"> </span><span class="s1">'pgoutput'</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">-- Create publication
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">CREATE</span><span class="w"> </span><span class="n">PUBLICATION</span><span class="w"> </span><span class="n">geode_pub</span><span class="w"> </span><span class="k">FOR</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">customers</span><span class="p">,</span><span class="w"> </span><span class="n">products</span><span class="p">,</span><span class="w"> </span><span class="n">orders</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div>
<h4 id="cdc-consumer" class="position-relative d-flex align-items-center group">
<span>CDC Consumer</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="cdc-consumer"
aria-haspopup="dialog"
aria-label="Share link: CDC Consumer">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">asyncio</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">psycopg</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">psycopg</span> <span class="kn">import</span> <span class="n">sql</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">geode_client</span> <span class="kn">import</span> <span class="n">Client</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">CDCConsumer</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">pg_config</span><span class="p">,</span> <span class="n">geode_config</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">pg_config</span> <span class="o">=</span> <span class="n">pg_config</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">geode_config</span> <span class="o">=</span> <span class="n">geode_config</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">geode_client</span> <span class="o">=</span> <span class="kc">None</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">def</span> <span class="nf">connect</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">geode_client</span> <span class="o">=</span> <span class="n">Client</span><span class="p">(</span><span class="o">**</span><span class="bp">self</span><span class="o">.</span><span class="n">geode_config</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">def</span> <span class="nf">process_change</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">change</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Process a single CDC change event."""</span>
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">geode_client</span><span class="o">.</span><span class="n">connection</span><span class="p">()</span> <span class="k">as</span> <span class="n">conn</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">table</span> <span class="o">=</span> <span class="n">change</span><span class="p">[</span><span class="s1">'table'</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="n">operation</span> <span class="o">=</span> <span class="n">change</span><span class="p">[</span><span class="s1">'operation'</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="n">data</span> <span class="o">=</span> <span class="n">change</span><span class="p">[</span><span class="s1">'data'</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Map table to label</span>
</span></span><span class="line"><span class="cl"> <span class="n">label</span> <span class="o">=</span> <span class="n">table</span><span class="o">.</span><span class="n">title</span><span class="p">()</span><span class="o">.</span><span class="n">rstrip</span><span class="p">(</span><span class="s1">'s'</span><span class="p">)</span> <span class="c1"># customers -> Customer</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">operation</span> <span class="o">==</span> <span class="s1">'INSERT'</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="sa">f</span><span class="s2">"CREATE (n:</span><span class="si">{</span><span class="n">label</span><span class="si">}</span><span class="s2"> $props)"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s2">"props"</span><span class="p">:</span> <span class="n">data</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">elif</span> <span class="n">operation</span> <span class="o">==</span> <span class="s1">'UPDATE'</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">set_clause</span> <span class="o">=</span> <span class="s1">', '</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s2">"n.</span><span class="si">{</span><span class="n">k</span><span class="si">}</span><span class="s2"> = $</span><span class="si">{</span><span class="n">k</span><span class="si">}</span><span class="s2">"</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">data</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="sa">f</span><span class="s2">"MATCH (n:</span><span class="si">{</span><span class="n">label</span><span class="si">}</span><span class="s2"> </span><span class="se">{{</span><span class="s2">id: $id</span><span class="se">}}</span><span class="s2">) SET </span><span class="si">{</span><span class="n">set_clause</span><span class="si">}</span><span class="s2">"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">data</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">elif</span> <span class="n">operation</span> <span class="o">==</span> <span class="s1">'DELETE'</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="sa">f</span><span class="s2">"MATCH (n:</span><span class="si">{</span><span class="n">label</span><span class="si">}</span><span class="s2"> </span><span class="se">{{</span><span class="s2">id: $id</span><span class="se">}}</span><span class="s2">) DELETE n"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s2">"id"</span><span class="p">:</span> <span class="n">data</span><span class="p">[</span><span class="s1">'id'</span><span class="p">]}</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">def</span> <span class="nf">start_replication</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Start consuming CDC events."""</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">connect</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">conn</span> <span class="o">=</span> <span class="k">await</span> <span class="n">psycopg</span><span class="o">.</span><span class="n">AsyncConnection</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="o">**</span><span class="bp">self</span><span class="o">.</span><span class="n">pg_config</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">autocommit</span><span class="o">=</span><span class="kc">True</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span> <span class="k">as</span> <span class="n">cur</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># Start replication</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"SELECT * FROM pg_logical_slot_get_changes('geode_slot', NULL, NULL)"</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">cur</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">change</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">parse_change</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">process_change</span><span class="p">(</span><span class="n">change</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="nf">parse_change</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">row</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Parse PostgreSQL logical replication message."""</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># Implementation depends on output plugin format</span>
</span></span><span class="line"><span class="cl"> <span class="k">pass</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Run CDC consumer</span>
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
</span></span><span class="line"><span class="cl"> <span class="n">consumer</span> <span class="o">=</span> <span class="n">CDCConsumer</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="n">pg_config</span><span class="o">=</span><span class="p">{</span><span class="s2">"host"</span><span class="p">:</span> <span class="s2">"localhost"</span><span class="p">,</span> <span class="s2">"user"</span><span class="p">:</span> <span class="s2">"postgres"</span><span class="p">,</span> <span class="s2">"dbname"</span><span class="p">:</span> <span class="s2">"ecommerce"</span><span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="n">geode_config</span><span class="o">=</span><span class="p">{</span><span class="s2">"host"</span><span class="p">:</span> <span class="s2">"localhost"</span><span class="p">,</span> <span class="s2">"port"</span><span class="p">:</span> <span class="mi">3141</span><span class="p">,</span> <span class="s2">"skip_verify"</span><span class="p">:</span> <span class="kc">True</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">consumer</span><span class="o">.</span><span class="n">start_replication</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">main</span><span class="p">())</span>
</span></span></code></pre></div>
<h4 id="dual-write-pattern" class="position-relative d-flex align-items-center group">
<span>Dual-Write Pattern</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="dual-write-pattern"
aria-haspopup="dialog"
aria-label="Share link: Dual-Write Pattern">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>During migration, write to both databases:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">DualWriteRepository</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">pg_conn</span><span class="p">,</span> <span class="n">geode_client</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">pg</span> <span class="o">=</span> <span class="n">pg_conn</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">geode</span> <span class="o">=</span> <span class="n">geode_client</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">def</span> <span class="nf">create_customer</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">email</span><span class="p">,</span> <span class="n">age</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Write to both PostgreSQL and Geode."""</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># Write to PostgreSQL (primary)</span>
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">pg</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span> <span class="k">as</span> <span class="n">cur</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"INSERT INTO customers (name, email, age) VALUES (</span><span class="si">%s</span><span class="s2">, </span><span class="si">%s</span><span class="s2">, </span><span class="si">%s</span><span class="s2">) RETURNING id"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">email</span><span class="p">,</span> <span class="n">age</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">customer_id</span> <span class="o">=</span> <span class="p">(</span><span class="k">await</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchone</span><span class="p">())[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Write to Geode (secondary)</span>
</span></span><span class="line"><span class="cl"> <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">geode</span><span class="o">.</span><span class="n">connection</span><span class="p">()</span> <span class="k">as</span> <span class="n">conn</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"CREATE (:Customer {id: $id, name: $name, email: $email, age: $age})"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s2">"id"</span><span class="p">:</span> <span class="n">customer_id</span><span class="p">,</span> <span class="s2">"name"</span><span class="p">:</span> <span class="n">name</span><span class="p">,</span> <span class="s2">"email"</span><span class="p">:</span> <span class="n">email</span><span class="p">,</span> <span class="s2">"age"</span><span class="p">:</span> <span class="n">age</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># Log error but don't fail - PostgreSQL is source of truth</span>
</span></span><span class="line"><span class="cl"> <span class="n">logging</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Failed to write to Geode: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">customer_id</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">def</span> <span class="nf">query_customer_network</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">customer_id</span><span class="p">,</span> <span class="n">depth</span><span class="o">=</span><span class="mi">3</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Query from Geode for graph traversals."""</span>
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">geode</span><span class="o">.</span><span class="n">connection</span><span class="p">()</span> <span class="k">as</span> <span class="n">conn</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">page</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="sa">f</span><span class="s2">"""
</span></span></span><span class="line"><span class="cl"><span class="s2"> MATCH (c:Customer </span><span class="se">{{</span><span class="s2">id: $id</span><span class="se">}}</span><span class="s2">)-[:KNOWS*1..</span><span class="si">{</span><span class="n">depth</span><span class="si">}</span><span class="s2">]->(friend)
</span></span></span><span class="line"><span class="cl"><span class="s2"> RETURN DISTINCT friend
</span></span></span><span class="line"><span class="cl"><span class="s2"> """</span><span class="p">,</span> <span class="p">{</span><span class="s2">"id"</span><span class="p">:</span> <span class="n">customer_id</span><span class="p">})</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">page</span><span class="o">.</span><span class="n">rows</span>
</span></span></code></pre></div>
<h3 id="hybrid-operation-period" class="position-relative d-flex align-items-center group">
<span>Hybrid Operation Period</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="hybrid-operation-period"
aria-haspopup="dialog"
aria-label="Share link: Hybrid Operation Period">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="query-routing" class="position-relative d-flex align-items-center group">
<span>Query Routing</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="query-routing"
aria-haspopup="dialog"
aria-label="Share link: Query Routing">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Route queries to the appropriate database:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">QueryRouter</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">pg_conn</span><span class="p">,</span> <span class="n">geode_client</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">pg</span> <span class="o">=</span> <span class="n">pg_conn</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">geode</span> <span class="o">=</span> <span class="n">geode_client</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Define which queries go where</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">graph_patterns</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'KNOWS'</span><span class="p">,</span> <span class="s1">'FRIENDS'</span><span class="p">,</span> <span class="s1">'FOLLOWS'</span><span class="p">,</span> <span class="c1"># Social relationships</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'PURCHASED'</span><span class="p">,</span> <span class="s1">'VIEWED'</span><span class="p">,</span> <span class="c1"># Customer behavior</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'REPORTS_TO'</span><span class="p">,</span> <span class="s1">'MANAGES'</span><span class="p">,</span> <span class="c1"># Hierarchies</span>
</span></span><span class="line"><span class="cl"> <span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="nf">should_use_graph</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">query</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Determine if query should go to graph database."""</span>
</span></span><span class="line"><span class="cl"> <span class="n">query_upper</span> <span class="o">=</span> <span class="n">query</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Check for relationship patterns</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">pattern</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">graph_patterns</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="sa">f</span><span class="s1">':</span><span class="si">{</span><span class="n">pattern</span><span class="si">}</span><span class="s1">'</span> <span class="ow">in</span> <span class="n">query_upper</span> <span class="ow">or</span> <span class="sa">f</span><span class="s1">'-[:</span><span class="si">{</span><span class="n">pattern</span><span class="si">}</span><span class="s1">'</span> <span class="ow">in</span> <span class="n">query_upper</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">True</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Check for path queries</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="s1">'*'</span> <span class="ow">in</span> <span class="n">query</span> <span class="ow">and</span> <span class="p">(</span><span class="s1">'-['</span> <span class="ow">in</span> <span class="n">query</span> <span class="ow">or</span> <span class="s1">'->'</span> <span class="ow">in</span> <span class="n">query</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">True</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">False</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">def</span> <span class="nf">execute</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Route and execute query."""</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">should_use_graph</span><span class="p">(</span><span class="n">query</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">geode</span><span class="o">.</span><span class="n">connection</span><span class="p">()</span> <span class="k">as</span> <span class="n">conn</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span> <span class="ow">or</span> <span class="p">{})</span>
</span></span><span class="line"><span class="cl"> <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># Translate to SQL if needed</span>
</span></span><span class="line"><span class="cl"> <span class="n">sql_query</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">translate_to_sql</span><span class="p">(</span><span class="n">query</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">pg</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span> <span class="k">as</span> <span class="n">cur</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">sql_query</span><span class="p">,</span> <span class="n">params</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="k">await</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
</span></span></code></pre></div>
<h4 id="data-consistency-checks" class="position-relative d-flex align-items-center group">
<span>Data Consistency Checks</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="data-consistency-checks"
aria-haspopup="dialog"
aria-label="Share link: Data Consistency Checks">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">verify_data_consistency</span><span class="p">(</span><span class="n">pg_conn</span><span class="p">,</span> <span class="n">geode_client</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Verify data is consistent between PostgreSQL and Geode."""</span>
</span></span><span class="line"><span class="cl"> <span class="n">discrepancies</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Check node counts</span>
</span></span><span class="line"><span class="cl"> <span class="n">tables_labels</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="p">(</span><span class="s1">'customers'</span><span class="p">,</span> <span class="s1">'Customer'</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="p">(</span><span class="s1">'products'</span><span class="p">,</span> <span class="s1">'Product'</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="p">(</span><span class="s1">'orders'</span><span class="p">,</span> <span class="s1">'Order'</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">table</span><span class="p">,</span> <span class="n">label</span> <span class="ow">in</span> <span class="n">tables_labels</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># PostgreSQL count</span>
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="n">pg_conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span> <span class="k">as</span> <span class="n">cur</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="sa">f</span><span class="s2">"SELECT COUNT(*) FROM </span><span class="si">{</span><span class="n">table</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">pg_count</span> <span class="o">=</span> <span class="p">(</span><span class="k">await</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchone</span><span class="p">())[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Geode count</span>
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="n">geode_client</span><span class="o">.</span><span class="n">connection</span><span class="p">()</span> <span class="k">as</span> <span class="n">conn</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">page</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="sa">f</span><span class="s2">"MATCH (n:</span><span class="si">{</span><span class="n">label</span><span class="si">}</span><span class="s2">) RETURN count(n)"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">geode_count</span> <span class="o">=</span> <span class="n">page</span><span class="o">.</span><span class="n">rows</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s1">'count(n)'</span><span class="p">]</span><span class="o">.</span><span class="n">as_int</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">pg_count</span> <span class="o">!=</span> <span class="n">geode_count</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">discrepancies</span><span class="o">.</span><span class="n">append</span><span class="p">({</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'type'</span><span class="p">:</span> <span class="s1">'count_mismatch'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'entity'</span><span class="p">:</span> <span class="n">label</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'postgresql'</span><span class="p">:</span> <span class="n">pg_count</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'geode'</span><span class="p">:</span> <span class="n">geode_count</span>
</span></span><span class="line"><span class="cl"> <span class="p">})</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Sample data verification</span>
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="n">pg_conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span> <span class="k">as</span> <span class="n">cur</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">"SELECT id, name, email FROM customers ORDER BY RANDOM() LIMIT 100"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">samples</span> <span class="o">=</span> <span class="k">await</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="n">geode_client</span><span class="o">.</span><span class="n">connection</span><span class="p">()</span> <span class="k">as</span> <span class="n">conn</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">pg_id</span><span class="p">,</span> <span class="n">pg_name</span><span class="p">,</span> <span class="n">pg_email</span> <span class="ow">in</span> <span class="n">samples</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">page</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">query</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"MATCH (c:Customer {id: $id}) RETURN c.name, c.email"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s2">"id"</span><span class="p">:</span> <span class="n">pg_id</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="ow">not</span> <span class="n">page</span><span class="o">.</span><span class="n">rows</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">discrepancies</span><span class="o">.</span><span class="n">append</span><span class="p">({</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'type'</span><span class="p">:</span> <span class="s1">'missing_node'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'entity'</span><span class="p">:</span> <span class="s1">'Customer'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'id'</span><span class="p">:</span> <span class="n">pg_id</span>
</span></span><span class="line"><span class="cl"> <span class="p">})</span>
</span></span><span class="line"><span class="cl"> <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">row</span> <span class="o">=</span> <span class="n">page</span><span class="o">.</span><span class="n">rows</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="s1">'c.name'</span><span class="p">]</span><span class="o">.</span><span class="n">as_string</span> <span class="o">!=</span> <span class="n">pg_name</span> <span class="ow">or</span> <span class="n">row</span><span class="p">[</span><span class="s1">'c.email'</span><span class="p">]</span><span class="o">.</span><span class="n">as_string</span> <span class="o">!=</span> <span class="n">pg_email</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">discrepancies</span><span class="o">.</span><span class="n">append</span><span class="p">({</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'type'</span><span class="p">:</span> <span class="s1">'data_mismatch'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'entity'</span><span class="p">:</span> <span class="s1">'Customer'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'id'</span><span class="p">:</span> <span class="n">pg_id</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'postgresql'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'name'</span><span class="p">:</span> <span class="n">pg_name</span><span class="p">,</span> <span class="s1">'email'</span><span class="p">:</span> <span class="n">pg_email</span><span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'geode'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'name'</span><span class="p">:</span> <span class="n">row</span><span class="p">[</span><span class="s1">'c.name'</span><span class="p">]</span><span class="o">.</span><span class="n">as_string</span><span class="p">,</span> <span class="s1">'email'</span><span class="p">:</span> <span class="n">row</span><span class="p">[</span><span class="s1">'c.email'</span><span class="p">]</span><span class="o">.</span><span class="n">as_string</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">})</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">discrepancies</span>
</span></span></code></pre></div>
<h3 id="migration-validation" class="position-relative d-flex align-items-center group">
<span>Migration Validation</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="migration-validation"
aria-haspopup="dialog"
aria-label="Share link: Migration Validation">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="comprehensive-validation-script" class="position-relative d-flex align-items-center group">
<span>Comprehensive Validation Script</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="comprehensive-validation-script"
aria-haspopup="dialog"
aria-label="Share link: Comprehensive Validation Script">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">run_migration_validation</span><span class="p">(</span><span class="n">pg_conn</span><span class="p">,</span> <span class="n">geode_client</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Run comprehensive migration validation."""</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"="</span> <span class="o">*</span> <span class="mi">60</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"MIGRATION VALIDATION REPORT"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"="</span> <span class="o">*</span> <span class="mi">60</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># 1. Count validation</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">1. NODE COUNT VALIDATION"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"-"</span> <span class="o">*</span> <span class="mi">40</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">entities</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="p">(</span><span class="s1">'customers'</span><span class="p">,</span> <span class="s1">'Customer'</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="p">(</span><span class="s1">'products'</span><span class="p">,</span> <span class="s1">'Product'</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="p">(</span><span class="s1">'categories'</span><span class="p">,</span> <span class="s1">'Category'</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="p">(</span><span class="s1">'orders'</span><span class="p">,</span> <span class="s1">'Order'</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">all_counts_match</span> <span class="o">=</span> <span class="kc">True</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">table</span><span class="p">,</span> <span class="n">label</span> <span class="ow">in</span> <span class="n">entities</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="n">pg_conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span> <span class="k">as</span> <span class="n">cur</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="sa">f</span><span class="s2">"SELECT COUNT(*) FROM </span><span class="si">{</span><span class="n">table</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">pg_count</span> <span class="o">=</span> <span class="p">(</span><span class="k">await</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchone</span><span class="p">())[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="n">geode_client</span><span class="o">.</span><span class="n">connection</span><span class="p">()</span> <span class="k">as</span> <span class="n">conn</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">page</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="sa">f</span><span class="s2">"MATCH (n:</span><span class="si">{</span><span class="n">label</span><span class="si">}</span><span class="s2">) RETURN count(n) AS c"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">geode_count</span> <span class="o">=</span> <span class="n">page</span><span class="o">.</span><span class="n">rows</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s1">'c'</span><span class="p">]</span><span class="o">.</span><span class="n">as_int</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">status</span> <span class="o">=</span> <span class="s2">"PASS"</span> <span class="k">if</span> <span class="n">pg_count</span> <span class="o">==</span> <span class="n">geode_count</span> <span class="k">else</span> <span class="s2">"FAIL"</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">status</span> <span class="o">==</span> <span class="s2">"FAIL"</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">all_counts_match</span> <span class="o">=</span> <span class="kc">False</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" </span><span class="si">{</span><span class="n">label</span><span class="si">}</span><span class="s2">: PG=</span><span class="si">{</span><span class="n">pg_count</span><span class="si">}</span><span class="s2">, Geode=</span><span class="si">{</span><span class="n">geode_count</span><span class="si">}</span><span class="s2"> [</span><span class="si">{</span><span class="n">status</span><span class="si">}</span><span class="s2">]"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># 2. Relationship count validation</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">2. RELATIONSHIP COUNT VALIDATION"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"-"</span> <span class="o">*</span> <span class="mi">40</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">relationships</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="p">(</span><span class="s2">"SELECT COUNT(*) FROM order_items"</span><span class="p">,</span> <span class="s2">"MATCH ()-[r:CONTAINS]->() RETURN count(r)"</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="p">(</span><span class="s2">"SELECT COUNT(*) FROM reviews"</span><span class="p">,</span> <span class="s2">"MATCH ()-[r:REVIEWED]->() RETURN count(r)"</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="p">(</span><span class="s2">"SELECT COUNT(*) FROM products WHERE category_id IS NOT NULL"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"MATCH ()-[r:IN_CATEGORY]->() RETURN count(r)"</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">pg_query</span><span class="p">,</span> <span class="n">gql_query</span> <span class="ow">in</span> <span class="n">relationships</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="n">pg_conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span> <span class="k">as</span> <span class="n">cur</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">pg_query</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">pg_count</span> <span class="o">=</span> <span class="p">(</span><span class="k">await</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchone</span><span class="p">())[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="n">geode_client</span><span class="o">.</span><span class="n">connection</span><span class="p">()</span> <span class="k">as</span> <span class="n">conn</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">page</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">gql_query</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">geode_count</span> <span class="o">=</span> <span class="n">page</span><span class="o">.</span><span class="n">rows</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s1">'count(r)'</span><span class="p">]</span><span class="o">.</span><span class="n">as_int</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">rel_type</span> <span class="o">=</span> <span class="n">gql_query</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">':'</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">']'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="n">status</span> <span class="o">=</span> <span class="s2">"PASS"</span> <span class="k">if</span> <span class="n">pg_count</span> <span class="o">==</span> <span class="n">geode_count</span> <span class="k">else</span> <span class="s2">"FAIL"</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" </span><span class="si">{</span><span class="n">rel_type</span><span class="si">}</span><span class="s2">: PG=</span><span class="si">{</span><span class="n">pg_count</span><span class="si">}</span><span class="s2">, Geode=</span><span class="si">{</span><span class="n">geode_count</span><span class="si">}</span><span class="s2"> [</span><span class="si">{</span><span class="n">status</span><span class="si">}</span><span class="s2">]"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># 3. Data integrity validation</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">3. DATA INTEGRITY VALIDATION"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"-"</span> <span class="o">*</span> <span class="mi">40</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Check referential integrity</span>
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="n">geode_client</span><span class="o">.</span><span class="n">connection</span><span class="p">()</span> <span class="k">as</span> <span class="n">conn</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># Orders should have customers</span>
</span></span><span class="line"><span class="cl"> <span class="n">page</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="s2">"""
</span></span></span><span class="line"><span class="cl"><span class="s2"> MATCH (o:Order)
</span></span></span><span class="line"><span class="cl"><span class="s2"> WHERE NOT (o)<-[:PLACED]-(:Customer)
</span></span></span><span class="line"><span class="cl"><span class="s2"> RETURN count(o) AS orphaned
</span></span></span><span class="line"><span class="cl"><span class="s2"> """</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">orphaned_orders</span> <span class="o">=</span> <span class="n">page</span><span class="o">.</span><span class="n">rows</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s1">'orphaned'</span><span class="p">]</span><span class="o">.</span><span class="n">as_int</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" Orphaned orders: </span><span class="si">{</span><span class="n">orphaned_orders</span><span class="si">}</span><span class="s2"> [</span><span class="si">{</span><span class="s1">'FAIL'</span> <span class="k">if</span> <span class="n">orphaned_orders</span> <span class="o">></span> <span class="mi">0</span> <span class="k">else</span> <span class="s1">'PASS'</span><span class="si">}</span><span class="s2">]"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Order items should have products</span>
</span></span><span class="line"><span class="cl"> <span class="n">page</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="s2">"""
</span></span></span><span class="line"><span class="cl"><span class="s2"> MATCH (o:Order)-[c:CONTAINS]->()
</span></span></span><span class="line"><span class="cl"><span class="s2"> WHERE NOT ()-[c]->(:Product)
</span></span></span><span class="line"><span class="cl"><span class="s2"> RETURN count(c) AS orphaned
</span></span></span><span class="line"><span class="cl"><span class="s2"> """</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">orphaned_items</span> <span class="o">=</span> <span class="n">page</span><span class="o">.</span><span class="n">rows</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s1">'orphaned'</span><span class="p">]</span><span class="o">.</span><span class="n">as_int</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" Orphaned order items: </span><span class="si">{</span><span class="n">orphaned_items</span><span class="si">}</span><span class="s2"> [</span><span class="si">{</span><span class="s1">'FAIL'</span> <span class="k">if</span> <span class="n">orphaned_items</span> <span class="o">></span> <span class="mi">0</span> <span class="k">else</span> <span class="s1">'PASS'</span><span class="si">}</span><span class="s2">]"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># 4. Query equivalence validation</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">4. QUERY EQUIVALENCE VALIDATION"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"-"</span> <span class="o">*</span> <span class="mi">40</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">test_queries</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'name'</span><span class="p">:</span> <span class="s1">'Top customers by order count'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'sql'</span><span class="p">:</span> <span class="s2">"""
</span></span></span><span class="line"><span class="cl"><span class="s2"> SELECT c.name, COUNT(o.id) as order_count
</span></span></span><span class="line"><span class="cl"><span class="s2"> FROM customers c
</span></span></span><span class="line"><span class="cl"><span class="s2"> LEFT JOIN orders o ON c.id = o.customer_id
</span></span></span><span class="line"><span class="cl"><span class="s2"> GROUP BY c.id, c.name
</span></span></span><span class="line"><span class="cl"><span class="s2"> ORDER BY order_count DESC
</span></span></span><span class="line"><span class="cl"><span class="s2"> LIMIT 5
</span></span></span><span class="line"><span class="cl"><span class="s2"> """</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'gql'</span><span class="p">:</span> <span class="s2">"""
</span></span></span><span class="line"><span class="cl"><span class="s2"> MATCH (c:Customer)
</span></span></span><span class="line"><span class="cl"><span class="s2"> OPTIONAL MATCH (c)-[:PLACED]->(o:Order)
</span></span></span><span class="line"><span class="cl"><span class="s2"> RETURN c.name, count(o) AS order_count
</span></span></span><span class="line"><span class="cl"><span class="s2"> ORDER BY order_count DESC
</span></span></span><span class="line"><span class="cl"><span class="s2"> LIMIT 5
</span></span></span><span class="line"><span class="cl"><span class="s2"> """</span>
</span></span><span class="line"><span class="cl"> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'name'</span><span class="p">:</span> <span class="s1">'Products by category'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'sql'</span><span class="p">:</span> <span class="s2">"""
</span></span></span><span class="line"><span class="cl"><span class="s2"> SELECT cat.name, COUNT(p.id)
</span></span></span><span class="line"><span class="cl"><span class="s2"> FROM categories cat
</span></span></span><span class="line"><span class="cl"><span class="s2"> LEFT JOIN products p ON p.category_id = cat.id
</span></span></span><span class="line"><span class="cl"><span class="s2"> GROUP BY cat.id, cat.name
</span></span></span><span class="line"><span class="cl"><span class="s2"> """</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'gql'</span><span class="p">:</span> <span class="s2">"""
</span></span></span><span class="line"><span class="cl"><span class="s2"> MATCH (cat:Category)
</span></span></span><span class="line"><span class="cl"><span class="s2"> OPTIONAL MATCH (p:Product)-[:IN_CATEGORY]->(cat)
</span></span></span><span class="line"><span class="cl"><span class="s2"> RETURN cat.name, count(p)
</span></span></span><span class="line"><span class="cl"><span class="s2"> """</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">test</span> <span class="ow">in</span> <span class="n">test_queries</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="n">pg_conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span> <span class="k">as</span> <span class="n">cur</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">test</span><span class="p">[</span><span class="s1">'sql'</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"> <span class="n">pg_results</span> <span class="o">=</span> <span class="k">await</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="n">geode_client</span><span class="o">.</span><span class="n">connection</span><span class="p">()</span> <span class="k">as</span> <span class="n">conn</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">page</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">test</span><span class="p">[</span><span class="s1">'gql'</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"> <span class="n">geode_results</span> <span class="o">=</span> <span class="p">[(</span><span class="n">r</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">as_string</span><span class="p">,</span> <span class="n">r</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">as_int</span><span class="p">)</span> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span>
</span></span><span class="line"><span class="cl"> <span class="p">[(</span><span class="n">row</span><span class="o">.</span><span class="n">values</span><span class="p">()[</span><span class="mi">0</span><span class="p">],</span> <span class="n">row</span><span class="o">.</span><span class="n">values</span><span class="p">()[</span><span class="mi">1</span><span class="p">])</span> <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">page</span><span class="o">.</span><span class="n">rows</span><span class="p">]]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Compare first few results</span>
</span></span><span class="line"><span class="cl"> <span class="k">match</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">pg_results</span><span class="p">)</span> <span class="o">==</span> <span class="nb">len</span><span class="p">(</span><span class="n">geode_results</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" </span><span class="si">{</span><span class="n">test</span><span class="p">[</span><span class="s1">'name'</span><span class="p">]</span><span class="si">}</span><span class="s2">: [</span><span class="si">{</span><span class="s1">'PASS'</span> <span class="k">if</span> <span class="n">match</span> <span class="k">else</span> <span class="s1">'FAIL'</span><span class="si">}</span><span class="s2">]"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span> <span class="o">+</span> <span class="s2">"="</span> <span class="o">*</span> <span class="mi">60</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"VALIDATION COMPLETE"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"="</span> <span class="o">*</span> <span class="mi">60</span><span class="p">)</span>
</span></span></code></pre></div>
<h3 id="common-pitfalls" class="position-relative d-flex align-items-center group">
<span>Common Pitfalls</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="common-pitfalls"
aria-haspopup="dialog"
aria-label="Share link: Common Pitfalls">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="1-losing-referential-integrity" class="position-relative d-flex align-items-center group">
<span>1. Losing Referential Integrity</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="1-losing-referential-integrity"
aria-haspopup="dialog"
aria-label="Share link: 1. Losing Referential Integrity">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>Problem</strong>: Foreign key constraints aren’t automatically enforced.</p>
<p><strong>Solution</strong>: Create application-level validation or use Geode constraints.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">//</span><span class="w"> </span><span class="py">Create</span><span class="w"> </span><span class="py">constraints</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="py">CONSTRAINT</span><span class="w"> </span><span class="py">customer_id_unique</span><span class="w"> </span><span class="py">ON</span><span class="w"> </span><span class="p">:</span><span class="nc">Customer</span><span class="p">(</span><span class="py">id</span><span class="p">)</span><span class="w"> </span><span class="py">ASSERT</span><span class="w"> </span><span class="py">UNIQUE</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="py">CONSTRAINT</span><span class="w"> </span><span class="py">order_customer_exists</span><span class="w"> </span><span class="py">ON</span><span class="w"> </span><span class="p">:</span><span class="nc">Order</span><span class="p">(</span><span class="py">customer_id</span><span class="p">)</span><span class="w"> </span><span class="py">ASSERT</span><span class="w"> </span><span class="py">EXISTS</span><span class="w">
</span></span></span></code></pre></div>
<h4 id="2-n1-query-pattern" class="position-relative d-flex align-items-center group">
<span>2. N+1 Query Pattern</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="2-n1-query-pattern"
aria-haspopup="dialog"
aria-label="Share link: 2. N&#43;1 Query Pattern">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>Problem</strong>: Fetching related data with multiple queries.</p>
<p><strong>Solution</strong>: Use graph patterns to fetch all related data at once.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">//</span><span class="w"> </span><span class="py">Instead</span><span class="w"> </span><span class="py">of</span><span class="w"> </span><span class="py">multiple</span><span class="w"> </span><span class="py">queries</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="err">//</span><span class="w"> </span><span class="py">Query</span><span class="w"> </span><span class="py">1</span><span class="p">:</span><span class="w"> </span><span class="nc">Get</span><span class="w"> </span><span class="py">customer</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="err">//</span><span class="w"> </span><span class="py">Query</span><span class="w"> </span><span class="py">2</span><span class="p">:</span><span class="w"> </span><span class="nc">Get</span><span class="w"> </span><span class="py">orders</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="err">//</span><span class="w"> </span><span class="py">Query</span><span class="w"> </span><span class="py">3</span><span class="p">:</span><span class="w"> </span><span class="nc">Get</span><span class="w"> </span><span class="py">products</span><span class="w"> </span><span class="py">for</span><span class="w"> </span><span class="py">each</span><span class="w"> </span><span class="py">order</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="err">//</span><span class="w"> </span><span class="py">Use</span><span class="w"> </span><span class="py">a</span><span class="w"> </span><span class="py">single</span><span class="w"> </span><span class="kd">query</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nc">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">c</span><span class="p">:</span><span class="nc">Customer</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nv">$id</span><span class="p">})</span><span class="err">-</span><span class="p">[:</span><span class="nc">PLACED</span><span class="p">]</span><span class="err">-></span><span class="p">(</span><span class="nc">o</span><span class="p">:</span><span class="nc">Order</span><span class="p">)</span><span class="err">-</span><span class="p">[:</span><span class="nc">CONTAINS</span><span class="p">]</span><span class="err">-></span><span class="p">(</span><span class="py">p</span><span class="p">:</span><span class="nc">Product</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">RETURN</span><span class="w"> </span><span class="py">c</span><span class="p">,</span><span class="w"> </span><span class="py">o</span><span class="p">,</span><span class="w"> </span><span class="py">p</span><span class="w">
</span></span></span></code></pre></div>
<h4 id="3-missing-indexes" class="position-relative d-flex align-items-center group">
<span>3. Missing Indexes</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="3-missing-indexes"
aria-haspopup="dialog"
aria-label="Share link: 3. Missing Indexes">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>Problem</strong>: Slow queries due to missing indexes.</p>
<p><strong>Solution</strong>: Create indexes for frequently queried properties.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="py">CREATE</span><span class="w"> </span><span class="py">INDEX</span><span class="w"> </span><span class="py">customer_email</span><span class="w"> </span><span class="py">ON</span><span class="w"> </span><span class="p">:</span><span class="nc">Customer</span><span class="p">(</span><span class="py">email</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="py">INDEX</span><span class="w"> </span><span class="py">product_name</span><span class="w"> </span><span class="py">ON</span><span class="w"> </span><span class="p">:</span><span class="nc">Product</span><span class="p">(</span><span class="py">name</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="py">INDEX</span><span class="w"> </span><span class="py">order_date</span><span class="w"> </span><span class="py">ON</span><span class="w"> </span><span class="p">:</span><span class="nc">Order</span><span class="p">(</span><span class="py">order_date</span><span class="p">)</span><span class="w">
</span></span></span></code></pre></div>
<h4 id="4-over-normalization" class="position-relative d-flex align-items-center group">
<span>4. Over-normalization</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="4-over-normalization"
aria-haspopup="dialog"
aria-label="Share link: 4. Over-normalization">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>Problem</strong>: Creating too many node types for simple values.</p>
<p><strong>Solution</strong>: Use properties for simple values, nodes for entities.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">//</span><span class="w"> </span><span class="py">Bad</span><span class="p">:</span><span class="w"> </span><span class="nc">Over</span><span class="err">-</span><span class="py">normalized</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(:</span><span class="nc">Customer</span><span class="p">)</span><span class="err">-</span><span class="p">[:</span><span class="nc">HAS_EMAIL</span><span class="p">]</span><span class="err">-></span><span class="p">(:</span><span class="nc">Email</span><span class="w"> </span><span class="p">{</span><span class="py">address</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">alice</span><span class="nd">@example</span><span class="err">.</span><span class="py">com</span><span class="err">'</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="err">//</span><span class="w"> </span><span class="py">Good</span><span class="p">:</span><span class="w"> </span><span class="nc">Property</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(:</span><span class="nc">Customer</span><span class="w"> </span><span class="p">{</span><span class="py">email</span><span class="p">:</span><span class="w"> </span><span class="err">'</span><span class="nc">alice</span><span class="nd">@example</span><span class="err">.</span><span class="py">com</span><span class="err">'</span><span class="p">})</span><span class="w">
</span></span></span></code></pre></div>
<h4 id="5-ignoring-null-semantics" class="position-relative d-flex align-items-center group">
<span>5. Ignoring NULL Semantics</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="5-ignoring-null-semantics"
aria-haspopup="dialog"
aria-label="Share link: 5. Ignoring NULL Semantics">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>Problem</strong>: Different NULL handling between SQL and GQL.</p>
<p><strong>Solution</strong>: Use COALESCE and explicit NULL checks.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">c</span><span class="p">:</span><span class="nc">Customer</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">WHERE</span><span class="w"> </span><span class="py">c</span><span class="err">.</span><span class="py">middle_name</span><span class="w"> </span><span class="py">IS</span><span class="w"> </span><span class="py">NOT</span><span class="w"> </span><span class="py">NULL</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">RETURN</span><span class="w"> </span><span class="py">c</span><span class="err">.</span><span class="py">name</span><span class="p">,</span><span class="w"> </span><span class="py">COALESCE</span><span class="p">(</span><span class="py">c</span><span class="err">.</span><span class="py">nickname</span><span class="p">,</span><span class="w"> </span><span class="py">c</span><span class="err">.</span><span class="py">name</span><span class="p">)</span><span class="w"> </span><span class="py">AS</span><span class="w"> </span><span class="py">display_name</span><span class="w">
</span></span></span></code></pre></div>
<h3 id="migration-checklist" class="position-relative d-flex align-items-center group">
<span>Migration Checklist</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="migration-checklist"
aria-haspopup="dialog"
aria-label="Share link: Migration Checklist">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="pre-migration" class="position-relative d-flex align-items-center group">
<span>Pre-Migration</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="pre-migration"
aria-haspopup="dialog"
aria-label="Share link: Pre-Migration">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><ul>
<li><input disabled="" type="checkbox"> Analyze PostgreSQL schema complexity</li>
<li><input disabled="" type="checkbox"> Identify tables suitable for graph modeling</li>
<li><input disabled="" type="checkbox"> Document all foreign key relationships</li>
<li><input disabled="" type="checkbox"> Assess query patterns and performance requirements</li>
<li><input disabled="" type="checkbox"> Plan hybrid operation period</li>
</ul>
<h4 id="schema-migration" class="position-relative d-flex align-items-center group">
<span>Schema Migration</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="schema-migration"
aria-haspopup="dialog"
aria-label="Share link: Schema Migration">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><ul>
<li><input disabled="" type="checkbox"> Design node labels and properties</li>
<li><input disabled="" type="checkbox"> Design relationship types and properties</li>
<li><input disabled="" type="checkbox"> Create Geode schema (indexes, constraints)</li>
<li><input disabled="" type="checkbox"> Document schema mapping</li>
</ul>
<h4 id="data-migration" class="position-relative d-flex align-items-center group">
<span>Data Migration</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="data-migration"
aria-haspopup="dialog"
aria-label="Share link: Data Migration">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><ul>
<li><input disabled="" type="checkbox"> Create ETL pipeline</li>
<li><input disabled="" type="checkbox"> Test with sample data</li>
<li><input disabled="" type="checkbox"> Run full data migration</li>
<li><input disabled="" type="checkbox"> Validate row/node counts</li>
<li><input disabled="" type="checkbox"> Validate relationship counts</li>
</ul>
<h4 id="application-migration" class="position-relative d-flex align-items-center group">
<span>Application Migration</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="application-migration"
aria-haspopup="dialog"
aria-label="Share link: Application Migration">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><ul>
<li><input disabled="" type="checkbox"> Update data access layer</li>
<li><input disabled="" type="checkbox"> Translate SQL queries to GQL</li>
<li><input disabled="" type="checkbox"> Implement dual-write if needed</li>
<li><input disabled="" type="checkbox"> Update connection configuration</li>
<li><input disabled="" type="checkbox"> Test all CRUD operations</li>
</ul>
<h4 id="validation" class="position-relative d-flex align-items-center group">
<span>Validation</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="validation"
aria-haspopup="dialog"
aria-label="Share link: Validation">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><ul>
<li><input disabled="" type="checkbox"> Run data consistency checks</li>
<li><input disabled="" type="checkbox"> Execute query equivalence tests</li>
<li><input disabled="" type="checkbox"> Perform load testing</li>
<li><input disabled="" type="checkbox"> Verify backup/restore procedures</li>
</ul>
<h4 id="cutover" class="position-relative d-flex align-items-center group">
<span>Cutover</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="cutover"
aria-haspopup="dialog"
aria-label="Share link: Cutover">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><ul>
<li><input disabled="" type="checkbox"> Plan maintenance window</li>
<li><input disabled="" type="checkbox"> Prepare rollback procedure</li>
<li><input disabled="" type="checkbox"> Execute final data sync</li>
<li><input disabled="" type="checkbox"> Switch application to Geode</li>
<li><input disabled="" type="checkbox"> Monitor for errors</li>
<li><input disabled="" type="checkbox"> Decommission PostgreSQL integration</li>
</ul>
<h3 id="resources" class="position-relative d-flex align-items-center group">
<span>Resources</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="resources"
aria-haspopup="dialog"
aria-label="Share link: Resources">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3><ul>
<li><a
href="/docs/gql-reference/"
>GQL Reference</a>
</li>
<li><a
href="/guides/graph-modeling/"
>Graph Modeling Guide</a>
</li>
<li><a
href="/guides/query-performance/"
>Query Performance</a>
</li>
<li><a
href="/clients/"
>Client Libraries</a>
</li>
</ul>
<h3 id="getting-help" class="position-relative d-flex align-items-center group">
<span>Getting Help</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="getting-help"
aria-haspopup="dialog"
aria-label="Share link: Getting Help">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3><p>If you encounter issues during migration:</p>
<ul>
<li><a
href="https://docs.geodedb.com"
aria-label="Documentation – opens in new window"
target="_blank" rel="noopener noreferrer"
>Documentation
<span aria-hidden="true" class="external-icon">↗</span>
</a>
</li>
<li><a
href="https://gitlab.com/devnw/codepros/geode/geode/-/issues"
aria-label="GitLab Issues – opens in new window"
target="_blank" rel="noopener noreferrer"
>GitLab Issues
<span aria-hidden="true" class="external-icon">↗</span>
</a>
</li>
<li><a
href="https://forum.geodedb.com"
aria-label="Community Forum – opens in new window"
target="_blank" rel="noopener noreferrer"
>Community Forum
<span aria-hidden="true" class="external-icon">↗</span>
</a>
</li>
<li><a
href="mailto:[email protected]"
>Email Support</a>
</li>
</ul>
Migrating from PostgreSQL to Geode
Complete guide to migrating from PostgreSQL to Geode, including relational to graph model conversion, ETL pipelines, and incremental migration strategies
19 min read