<!-- CANARY: REQ=REQ-DOCS-001; FEATURE="Docs"; ASPECT=Documentation; STATUS=TESTED; OWNER=docs; UPDATED=2026-01-15 -->
<h2 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>
</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>Data migration is the process of transferring data from one system to another, often involving format transformation, schema mapping, and data quality validation. Geode provides comprehensive tools and strategies for smooth, reliable data migrations.</p>
<h3 id="migration-strategies" class="position-relative d-flex align-items-center group">
<span>Migration Strategies</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-strategies"
aria-haspopup="dialog"
aria-label="Share link: Migration Strategies">
<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="big-bang-migration" class="position-relative d-flex align-items-center group">
<span>Big Bang 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="big-bang-migration"
aria-haspopup="dialog"
aria-label="Share link: Big Bang 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><p>Move all data at once:</p>
<p><strong>Pros:</strong></p>
<ul>
<li>Simple and straightforward</li>
<li>Immediate cutover</li>
<li>No sync period</li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li>Higher risk</li>
<li>Longer downtime</li>
<li>Difficult rollback</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Stop old system</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Export all data</span>
</span></span><span class="line"><span class="cl">geode <span class="nb">export</span> --source legacy_db --output data.json
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Import to Geode</span>
</span></span><span class="line"><span class="cl">geode import --input data.json --graph production
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Start new system</span>
</span></span></code></pre></div>
<h4 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>
</h4><p>Migrate data in phases:</p>
<p><strong>Pros:</strong></p>
<ul>
<li>Lower risk</li>
<li>Phased validation</li>
<li>Easier rollback</li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li>More complex</li>
<li>Requires sync</li>
<li>Longer timeline</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Phase 1: Users</span>
</span></span><span class="line"><span class="cl">geode import --input users.json --graph production
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Phase 2: Relationships</span>
</span></span><span class="line"><span class="cl">geode import --input relationships.json --graph production
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Phase 3: Activity data</span>
</span></span><span class="line"><span class="cl">geode import --input activities.json --graph production
</span></span></code></pre></div>
<h4 id="parallel-run" class="position-relative d-flex align-items-center group">
<span>Parallel Run</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="parallel-run"
aria-haspopup="dialog"
aria-label="Share link: Parallel Run">
<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>Run old and new systems simultaneously:</p>
<p><strong>Pros:</strong></p>
<ul>
<li>Lowest risk</li>
<li>Validate in production</li>
<li>Gradual transition</li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li>Most complex</li>
<li>Highest cost</li>
<li>Sync overhead</li>
</ul>
<h3 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>
</h3>
<h4 id="schema-versioning" class="position-relative d-flex align-items-center group">
<span>Schema Versioning</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-versioning"
aria-haspopup="dialog"
aria-label="Share link: Schema Versioning">
<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>Track schema changes:</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="kd">schema</span><span class="w"> </span><span class="py">version</span><span class="w"> </span><span class="py">table</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">TABLE</span><span class="w"> </span><span class="kd">schema</span><span class="py">_versions</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">version</span><span class="w"> </span><span class="py">INTEGER</span><span class="w"> </span><span class="py">PRIMARY</span><span class="w"> </span><span class="py">KEY</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">description</span><span class="w"> </span><span class="py">STRING</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">applied_at</span><span class="w"> </span><span class="py">TIMESTAMP</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">applied_by</span><span class="w"> </span><span class="py">STRING</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">)</span><span class="err">;</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">Record</span><span class="w"> </span><span class="py">migration</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">INSERT</span><span class="w"> </span><span class="py">INTO</span><span class="w"> </span><span class="kd">schema</span><span class="py">_versions</span><span class="w"> </span><span class="py">VALUES</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">1</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="err">'</span><span class="py">Initial</span><span class="w"> </span><span class="kd">schema</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">NOW</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">CURRENT_USER</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="err">;</span><span class="w">
</span></span></span></code></pre></div>
<h4 id="schema-evolution" class="position-relative d-flex align-items-center group">
<span>Schema Evolution</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-evolution"
aria-haspopup="dialog"
aria-label="Share link: Schema Evolution">
<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>Handle breaking changes:</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">Add</span><span class="w"> </span><span class="py">new</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">ALTER</span><span class="w"> </span><span class="py">PROPERTY</span><span class="w"> </span><span class="py">TYPE</span><span class="w"> </span><span class="py">Person</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">ADD</span><span class="w"> </span><span class="py">COLUMN</span><span class="w"> </span><span class="py">middle_name</span><span class="w"> </span><span class="py">STRING</span><span class="err">;</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">Populate</span><span class="w"> </span><span class="py">from</span><span class="w"> </span><span class="py">existing</span><span class="w"> </span><span class="py">data</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">UPDATE</span><span class="w"> </span><span class="py">Person</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">middle_name</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">SPLIT_PART</span><span class="p">(</span><span class="py">full_name</span><span class="p">,</span><span class="w"> </span><span class="err">'</span><span class="w"> </span><span class="err">'</span><span class="p">,</span><span class="w"> </span><span class="py">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">WHERE</span><span class="w"> </span><span class="py">full_name</span><span class="w"> </span><span class="py">LIKE</span><span class="w"> </span><span class="err">'%</span><span class="w"> </span><span class="err">%</span><span class="w"> </span><span class="err">%';</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">Remove</span><span class="w"> </span><span class="py">old</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">ALTER</span><span class="w"> </span><span class="py">PROPERTY</span><span class="w"> </span><span class="py">TYPE</span><span class="w"> </span><span class="py">Person</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">DROP</span><span class="w"> </span><span class="py">COLUMN</span><span class="w"> </span><span class="py">full_name</span><span class="err">;</span><span class="w">
</span></span></span></code></pre></div>
<h3 id="data-transformation" class="position-relative d-flex align-items-center group">
<span>Data Transformation</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-transformation"
aria-haspopup="dialog"
aria-label="Share link: Data Transformation">
<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="type-conversion" class="position-relative d-flex align-items-center group">
<span>Type 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="type-conversion"
aria-haspopup="dialog"
aria-label="Share link: Type 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>
</h4><p>Convert data types:</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">String</span><span class="w"> </span><span class="py">to</span><span class="w"> </span><span class="py">date</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">UPDATE</span><span class="w"> </span><span class="py">Person</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">birth_date</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">TO_DATE</span><span class="p">(</span><span class="py">birth_date_string</span><span class="p">,</span><span class="w"> </span><span class="err">'</span><span class="py">YYYY</span><span class="err">-</span><span class="py">MM</span><span class="err">-</span><span class="py">DD</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">WHERE</span><span class="w"> </span><span class="py">birth_date</span><span class="w"> </span><span class="py">IS</span><span class="w"> </span><span class="py">NULL</span><span class="err">;</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">JSON</span><span class="w"> </span><span class="py">to</span><span class="w"> </span><span class="py">structured</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">UPDATE</span><span class="w"> </span><span class="py">Event</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">metadata_parsed</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">JSON_PARSE</span><span class="p">(</span><span class="py">metadata_string</span><span class="p">)</span><span class="err">;</span><span class="w">
</span></span></span></code></pre></div>
<h4 id="data-cleansing" class="position-relative d-flex align-items-center group">
<span>Data Cleansing</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-cleansing"
aria-haspopup="dialog"
aria-label="Share link: Data Cleansing">
<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>Clean and normalize data:</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">Trim</span><span class="w"> </span><span class="py">whitespace</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">UPDATE</span><span class="w"> </span><span class="py">Person</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">email</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">TRIM</span><span class="p">(</span><span class="py">LOWER</span><span class="p">(</span><span class="py">email</span><span class="p">))</span><span class="err">;</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">Standardize</span><span class="w"> </span><span class="py">phone</span><span class="w"> </span><span class="py">numbers</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">UPDATE</span><span class="w"> </span><span class="py">Contact</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">phone</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">REGEXP_REPLACE</span><span class="p">(</span><span class="py">phone</span><span class="p">,</span><span class="w"> </span><span class="err">'</span><span class="p">[</span><span class="err">^</span><span class="py">0</span><span class="err">-</span><span class="py">9</span><span class="p">]</span><span class="err">'</span><span class="p">,</span><span class="w"> </span><span class="err">''</span><span class="p">)</span><span class="err">;</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">Remove</span><span class="w"> </span><span class="py">duplicates</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">FROM</span><span class="w"> </span><span class="py">Person</span><span class="w"> </span><span class="py">p1</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">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="py">SELECT</span><span class="w"> </span><span class="py">1</span><span class="w"> </span><span class="py">FROM</span><span class="w"> </span><span class="py">Person</span><span class="w"> </span><span class="py">p2</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">p1</span><span class="err">.</span><span class="py">email</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">p2</span><span class="err">.</span><span class="py">email</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">AND</span><span class="w"> </span><span class="py">p1</span><span class="err">.</span><span class="py">id</span><span class="w"> </span><span class="err">></span><span class="w"> </span><span class="py">p2</span><span class="err">.</span><span class="py">id</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">)</span><span class="err">;</span><span class="w">
</span></span></span></code></pre></div>
<h3 id="migration-tools" class="position-relative d-flex align-items-center group">
<span>Migration Tools</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-tools"
aria-haspopup="dialog"
aria-label="Share link: Migration Tools">
<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="geode-cli" class="position-relative d-flex align-items-center group">
<span>Geode CLI</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="geode-cli"
aria-haspopup="dialog"
aria-label="Share link: Geode CLI">
<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>Command-line migration tools:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Export from SQL database</span>
</span></span><span class="line"><span class="cl">geode <span class="nb">export</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --source postgresql://localhost/mydb <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --output backup.json <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --format json
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Import to Geode</span>
</span></span><span class="line"><span class="cl">geode import <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --input backup.json <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --graph production <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --batch-size <span class="m">1000</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --parallel <span class="m">4</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Verify migration</span>
</span></span><span class="line"><span class="cl">geode validate <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --graph production <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --check-constraints <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --check-references
</span></span></code></pre></div>
<h4 id="python-migration-script" class="position-relative d-flex align-items-center group">
<span>Python Migration 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-migration-script"
aria-haspopup="dialog"
aria-label="Share link: Python Migration 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><p>Custom migration logic:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><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 class="kn">import</span> <span class="nn">asyncio</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">migrate_users</span><span class="p">(</span><span class="n">source_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">"""Migrate users from SQL to Geode"""</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># Extract from source</span>
</span></span><span class="line"><span class="cl"> <span class="n">users</span> <span class="o">=</span> <span class="k">await</span> <span class="n">source_conn</span><span class="o">.</span><span class="n">fetch</span><span class="p">(</span><span class="s2">"SELECT * FROM users"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">batch</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">user</span> <span class="ow">in</span> <span class="n">users</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># Transform</span>
</span></span><span class="line"><span class="cl"> <span class="n">node</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"labels"</span><span class="p">:</span> <span class="p">[</span><span class="s2">"User"</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"properties"</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"id"</span><span class="p">:</span> <span class="n">user</span><span class="p">[</span><span class="s1">'id'</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"name"</span><span class="p">:</span> <span class="n">user</span><span class="p">[</span><span class="s1">'name'</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"email"</span><span class="p">:</span> <span class="n">user</span><span class="p">[</span><span class="s1">'email'</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"created_at"</span><span class="p">:</span> <span class="n">user</span><span class="p">[</span><span class="s1">'created_at'</span><span class="p">]</span><span class="o">.</span><span class="n">isoformat</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="n">batch</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Load in batches</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">batch</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">1000</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">geode_client</span><span class="o">.</span><span class="n">create_nodes_batch</span><span class="p">(</span><span class="n">batch</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">batch</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"># Load remaining</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">batch</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">geode_client</span><span class="o">.</span><span class="n">create_nodes_batch</span><span class="p">(</span><span class="n">batch</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">main</span><span class="p">():</span>
</span></span><span class="line"><span class="cl"> <span class="n">source</span> <span class="o">=</span> <span class="k">await</span> <span class="n">connect_source</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="n">geode</span> <span class="o">=</span> <span class="n">Client</span><span class="p">(</span><span class="s2">"localhost"</span><span class="p">,</span> <span class="mi">3141</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">migrate_users</span><span class="p">(</span><span class="n">source</span><span class="p">,</span> <span class="n">geode</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">migrate_relationships</span><span class="p">(</span><span class="n">source</span><span class="p">,</span> <span class="n">geode</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">validate_migration</span><span class="p">(</span><span class="n">source</span><span class="p">,</span> <span class="n">geode</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>
<h3 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>
</h3>
<h4 id="data-quality-checks" class="position-relative d-flex align-items-center group">
<span>Data Quality 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-quality-checks"
aria-haspopup="dialog"
aria-label="Share link: Data Quality 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><p>Verify migration completeness:</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">Count</span><span class="w"> </span><span class="py">comparison</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">SELECT</span><span class="w"> </span><span class="err">'</span><span class="py">source</span><span class="err">'</span><span class="w"> </span><span class="py">AS</span><span class="w"> </span><span class="py">system</span><span class="p">,</span><span class="w"> </span><span class="py">COUNT</span><span class="p">(</span><span class="err">*</span><span class="p">)</span><span class="w"> </span><span class="py">AS</span><span class="w"> </span><span class="py">user_count</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">FROM</span><span class="w"> </span><span class="py">source_users</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kc">UNION</span><span class="w"> </span><span class="py">ALL</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">SELECT</span><span class="w"> </span><span class="err">'</span><span class="py">target</span><span class="err">'</span><span class="w"> </span><span class="py">AS</span><span class="w"> </span><span class="py">system</span><span class="p">,</span><span class="w"> </span><span class="py">COUNT</span><span class="p">(</span><span class="err">*</span><span class="p">)</span><span class="w"> </span><span class="py">AS</span><span class="w"> </span><span class="py">user_count</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">FROM</span><span class="w"> </span><span class="py">Person</span><span class="err">;</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">Sample</span><span class="w"> </span><span class="py">verification</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">SELECT</span><span class="w"> </span><span class="err">*</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">FROM</span><span class="w"> </span><span class="py">Person</span><span class="w"> </span><span class="py">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">NOT</span><span class="w"> </span><span class="py">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="py">SELECT</span><span class="w"> </span><span class="py">1</span><span class="w"> </span><span class="py">FROM</span><span class="w"> </span><span class="py">source_users</span><span class="w"> </span><span class="py">s</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">s</span><span class="err">.</span><span class="py">id</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">p</span><span class="err">.</span><span class="py">id</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">)</span><span class="err">;</span><span class="w">
</span></span></span></code></pre></div>
<h4 id="referential-integrity" class="position-relative d-flex align-items-center group">
<span>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="referential-integrity"
aria-haspopup="dialog"
aria-label="Share link: 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>Validate relationships:</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">Check</span><span class="w"> </span><span class="py">for</span><span class="w"> </span><span class="py">orphaned</span><span class="w"> </span><span class="py">edges</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">SELECT</span><span class="w"> </span><span class="py">e</span><span class="err">.*</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">FROM</span><span class="w"> </span><span class="py">FRIEND</span><span class="w"> </span><span class="py">e</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">NOT</span><span class="w"> </span><span class="py">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="py">SELECT</span><span class="w"> </span><span class="py">1</span><span class="w"> </span><span class="py">FROM</span><span class="w"> </span><span class="py">Person</span><span class="w"> </span><span class="py">p</span><span class="w"> </span><span class="py">WHERE</span><span class="w"> </span><span class="py">p</span><span class="err">.</span><span class="py">id</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">e</span><span class="err">.</span><span class="py">from_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="py">OR</span><span class="w"> </span><span class="py">NOT</span><span class="w"> </span><span class="py">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="py">SELECT</span><span class="w"> </span><span class="py">1</span><span class="w"> </span><span class="py">FROM</span><span class="w"> </span><span class="py">Person</span><span class="w"> </span><span class="py">p</span><span class="w"> </span><span class="py">WHERE</span><span class="w"> </span><span class="py">p</span><span class="err">.</span><span class="py">id</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">e</span><span class="err">.</span><span class="py">to_id</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">)</span><span class="err">;</span><span class="w">
</span></span></span></code></pre></div>
<h3 id="best-practices" class="position-relative d-flex align-items-center group">
<span>Best Practices</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="best-practices"
aria-haspopup="dialog"
aria-label="Share link: Best Practices">
<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="planning" class="position-relative d-flex align-items-center group">
<span>Planning</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="planning"
aria-haspopup="dialog"
aria-label="Share link: Planning">
<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>Document current state</li>
<li>Define success criteria</li>
<li>Create rollback plan</li>
<li>Test on copy first</li>
<li>Schedule during low-traffic</li>
</ul>
<h4 id="execution" class="position-relative d-flex align-items-center group">
<span>Execution</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="execution"
aria-haspopup="dialog"
aria-label="Share link: Execution">
<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>Use transactions</li>
<li>Batch operations</li>
<li>Monitor progress</li>
<li>Validate continuously</li>
<li>Keep audit trail</li>
</ul>
<h4 id="post-migration" class="position-relative d-flex align-items-center group">
<span>Post-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="post-migration"
aria-haspopup="dialog"
aria-label="Share link: Post-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>Verify data quality</li>
<li>Update documentation</li>
<li>Monitor performance</li>
<li>Gather feedback</li>
<li>Archive old data</li>
</ul>
<h3 id="related-topics" class="position-relative d-flex align-items-center group">
<span>Related Topics</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="related-topics"
aria-haspopup="dialog"
aria-label="Share link: Related Topics">
<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="/tags/import"
>Import</a>
- Data import operations</li>
<li><a
href="/tags/export"
>Export</a>
- Data export operations</li>
<li><a
href="/tags/etl"
>ETL</a>
- Extract Transform Load pipelines</li>
</ul>
<h3 id="advanced-migration-patterns" class="position-relative d-flex align-items-center group">
<span>Advanced Migration Patterns</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="advanced-migration-patterns"
aria-haspopup="dialog"
aria-label="Share link: Advanced Migration Patterns">
<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="zero-downtime-migration-strategy" class="position-relative d-flex align-items-center group">
<span>Zero-Downtime Migration Strategy</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="zero-downtime-migration-strategy"
aria-haspopup="dialog"
aria-label="Share link: Zero-Downtime Migration Strategy">
<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>Deploy changes without service interruption:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><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 class="kn">import</span> <span class="nn">asyncio</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">ZeroDowntimeMigration</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Manage migrations with zero downtime using dual-write pattern."""</span>
</span></span><span class="line"><span class="cl">
</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">old_db</span><span class="p">,</span> <span class="n">new_db</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">old_db</span> <span class="o">=</span> <span class="n">old_db</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">new_db</span> <span class="o">=</span> <span class="n">new_db</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">migration_complete</span> <span class="o">=</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">phase1_dual_write</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">"""Phase 1: Write to both old and new systems."""</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"Phase 1: Starting dual-write mode"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># All new writes go to both systems</span>
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">def</span> <span class="nf">write_user</span><span class="p">(</span><span class="n">user_data</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># Write to old system</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">old_db</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"> INSERT INTO users_table VALUES ($id, $name, $email)
</span></span></span><span class="line"><span class="cl"><span class="s2"> """</span><span class="p">,</span> <span class="n">user_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"># Write to new system (Geode)</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">new_db</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"> CREATE (u:User {
</span></span></span><span class="line"><span class="cl"><span class="s2"> id: $id,
</span></span></span><span class="line"><span class="cl"><span class="s2"> name: $name,
</span></span></span><span class="line"><span class="cl"><span class="s2"> email: $email,
</span></span></span><span class="line"><span class="cl"><span class="s2"> migrated_at: datetime()
</span></span></span><span class="line"><span class="cl"><span class="s2"> })
</span></span></span><span class="line"><span class="cl"><span class="s2"> """</span><span class="p">,</span> <span class="n">user_data</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">write_user</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">phase2_backfill</span><span class="p">(</span><span class="bp">self</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">"""Phase 2: Backfill historical data."""</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"Phase 2: Backfilling historical data"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">offset</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl"> <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># Read batch from old system</span>
</span></span><span class="line"><span class="cl"> <span class="n">old_users</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">old_db</span><span class="o">.</span><span class="n">fetch</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"> SELECT id, name, email, created_at
</span></span></span><span class="line"><span class="cl"><span class="s2"> FROM users_table
</span></span></span><span class="line"><span class="cl"><span class="s2"> ORDER BY id
</span></span></span><span class="line"><span class="cl"><span class="s2"> LIMIT </span><span class="si">{</span><span class="n">batch_size</span><span class="si">}</span><span class="s2"> OFFSET </span><span class="si">{</span><span class="n">offset</span><span class="si">}</span><span class="s2">
</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></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="ow">not</span> <span class="n">old_users</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">break</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Write to new system</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">new_db</span><span class="o">.</span><span class="n">transaction</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">new_db</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"> UNWIND $users AS user
</span></span></span><span class="line"><span class="cl"><span class="s2"> MERGE (u:User {id: user.id})
</span></span></span><span class="line"><span class="cl"><span class="s2"> ON CREATE SET
</span></span></span><span class="line"><span class="cl"><span class="s2"> u.name = user.name,
</span></span></span><span class="line"><span class="cl"><span class="s2"> u.email = user.email,
</span></span></span><span class="line"><span class="cl"><span class="s2"> u.created_at = user.created_at,
</span></span></span><span class="line"><span class="cl"><span class="s2"> u.backfilled = true
</span></span></span><span class="line"><span class="cl"><span class="s2"> """</span><span class="p">,</span> <span class="p">{</span><span class="s1">'users'</span><span class="p">:</span> <span class="n">old_users</span><span class="p">})</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">offset</span> <span class="o">+=</span> <span class="n">batch_size</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">"Backfilled </span><span class="si">{</span><span class="n">offset</span><span class="si">}</span><span class="s2"> users"</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">phase3_verify</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">"""Phase 3: Verify data consistency."""</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"Phase 3: Verifying data consistency"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Count records</span>
</span></span><span class="line"><span class="cl"> <span class="n">old_count</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">old_db</span><span class="o">.</span><span class="n">fetch_val</span><span class="p">(</span><span class="s2">"SELECT COUNT(*) FROM users_table"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">new_count</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">new_db</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">"MATCH (u:User) RETURN count(u) AS count"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">new_count</span> <span class="o">=</span> <span class="p">(</span><span class="n">new_count</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="k">if</span> <span class="n">new_count</span><span class="o">.</span><span class="n">rows</span> <span class="k">else</span> <span class="kc">None</span><span class="p">)[</span><span class="s1">'count'</span><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="n">old_count</span> <span class="o">!=</span> <span class="n">new_count</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">raise</span> <span class="n">MigrationError</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Count mismatch: </span><span class="si">{</span><span class="n">old_count</span><span class="si">}</span><span class="s2"> vs </span><span class="si">{</span><span class="n">new_count</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"># Sample verification</span>
</span></span><span class="line"><span class="cl"> <span class="n">sample_ids</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">old_db</span><span class="o">.</span><span class="n">fetch</span><span class="p">(</span><span class="s2">"SELECT id FROM users_table ORDER BY RANDOM() LIMIT 1000"</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">sample</span> <span class="ow">in</span> <span class="n">sample_ids</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">old_user</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">old_db</span><span class="o">.</span><span class="n">fetch_one</span><span class="p">(</span><span class="sa">f</span><span class="s2">"SELECT * FROM users_table WHERE id = </span><span class="si">{</span><span class="n">sample</span><span class="p">[</span><span class="s1">'id'</span><span class="p">]</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">new_user</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">new_db</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">"MATCH (u:User {id: $id}) RETURN u"</span><span class="p">,</span> <span class="p">{</span><span class="s1">'id'</span><span class="p">:</span> <span class="n">sample</span><span class="p">[</span><span class="s1">'id'</span><span class="p">]})</span>
</span></span><span class="line"><span class="cl"> <span class="n">new_user</span> <span class="o">=</span> <span class="n">new_user</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="k">if</span> <span class="n">new_user</span><span class="o">.</span><span class="n">rows</span> <span class="k">else</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">if</span> <span class="ow">not</span> <span class="n">new_user</span> <span class="ow">or</span> <span class="n">old_user</span><span class="p">[</span><span class="s1">'name'</span><span class="p">]</span> <span class="o">!=</span> <span class="n">new_user</span><span class="p">[</span><span class="s1">'u'</span><span class="p">][</span><span class="s1">'name'</span><span class="p">]:</span>
</span></span><span class="line"><span class="cl"> <span class="k">raise</span> <span class="n">MigrationError</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Data mismatch for user </span><span class="si">{</span><span class="n">sample</span><span class="p">[</span><span class="s1">'id'</span><span class="p">]</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">"Verification complete"</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">phase4_cutover</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">"""Phase 4: Switch reads to new system."""</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"Phase 4: Cutting over reads to new system"</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">migration_complete</span> <span class="o">=</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"># Usage</span>
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">run_zero_downtime_migration</span><span class="p">():</span>
</span></span><span class="line"><span class="cl"> <span class="n">old_postgres</span> <span class="o">=</span> <span class="n">PostgresClient</span><span class="p">(</span><span class="s2">"old-db:5432"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">new_geode</span> <span class="o">=</span> <span class="n">Client</span><span class="p">(</span><span class="s2">"new-geode:3141"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">migration</span> <span class="o">=</span> <span class="n">ZeroDowntimeMigration</span><span class="p">(</span><span class="n">old_postgres</span><span class="p">,</span> <span class="n">new_geode</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 phases</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">migration</span><span class="o">.</span><span class="n">phase1_dual_write</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">migration</span><span class="o">.</span><span class="n">phase2_backfill</span><span class="p">(</span><span class="n">batch_size</span><span class="o">=</span><span class="mi">10000</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">migration</span><span class="o">.</span><span class="n">phase3_verify</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">migration</span><span class="o">.</span><span class="n">phase4_cutover</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">"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="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">run_zero_downtime_migration</span><span class="p">())</span>
</span></span></code></pre></div>
<h4 id="schema-transformation-patterns" class="position-relative d-flex align-items-center group">
<span>Schema Transformation Patterns</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-transformation-patterns"
aria-haspopup="dialog"
aria-label="Share link: Schema Transformation Patterns">
<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>Transform relational schema to graph model:</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">RelationalToGraphTransformer</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Transform relational database schema to graph model."""</span>
</span></span><span class="line"><span class="cl">
</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">source_db</span><span class="p">,</span> <span class="n">target_graph</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">source</span> <span class="o">=</span> <span class="n">source_db</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">target</span> <span class="o">=</span> <span class="n">target_graph</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">migrate_entities</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">label</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Migrate table rows to graph nodes."""</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">"Migrating </span><span class="si">{</span><span class="n">table_name</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">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Read table schema</span>
</span></span><span class="line"><span class="cl"> <span class="n">columns</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">source</span><span class="o">.</span><span class="n">get_columns</span><span class="p">(</span><span class="n">table_name</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 data in batches</span>
</span></span><span class="line"><span class="cl"> <span class="n">offset</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl"> <span class="n">batch_size</span> <span class="o">=</span> <span class="mi">5000</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">while</span> <span class="kc">True</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="bp">self</span><span class="o">.</span><span class="n">source</span><span class="o">.</span><span class="n">fetch</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"> SELECT * FROM </span><span class="si">{</span><span class="n">table_name</span><span class="si">}</span><span class="s2">
</span></span></span><span class="line"><span class="cl"><span class="s2"> ORDER BY id
</span></span></span><span class="line"><span class="cl"><span class="s2"> LIMIT </span><span class="si">{</span><span class="n">batch_size</span><span class="si">}</span><span class="s2"> OFFSET </span><span class="si">{</span><span class="n">offset</span><span class="si">}</span><span class="s2">
</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></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="ow">not</span> <span class="n">rows</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">break</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Transform and insert</span>
</span></span><span class="line"><span class="cl"> <span class="n">nodes</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="n">col</span><span class="p">:</span> <span class="n">row</span><span class="p">[</span><span class="n">col</span><span class="p">]</span> <span class="k">for</span> <span class="n">col</span> <span class="ow">in</span> <span class="n">columns</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></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">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">target</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"> UNWIND $nodes AS node
</span></span></span><span class="line"><span class="cl"><span class="s2"> CREATE (n:</span><span class="si">{</span><span class="n">label</span><span class="si">}</span><span class="s2">)
</span></span></span><span class="line"><span class="cl"><span class="s2"> SET n = node
</span></span></span><span class="line"><span class="cl"><span class="s2"> """</span><span class="p">,</span> <span class="p">{</span><span class="s1">'nodes'</span><span class="p">:</span> <span class="n">nodes</span><span class="p">})</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">offset</span> <span class="o">+=</span> <span class="n">batch_size</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">" Migrated </span><span class="si">{</span><span class="n">offset</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">async</span> <span class="k">def</span> <span class="nf">migrate_foreign_keys</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fk_constraint</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Transform foreign keys to relationships."""</span>
</span></span><span class="line"><span class="cl"> <span class="n">table</span> <span class="o">=</span> <span class="n">fk_constraint</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">ref_table</span> <span class="o">=</span> <span class="n">fk_constraint</span><span class="p">[</span><span class="s1">'referenced_table'</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="n">fk_column</span> <span class="o">=</span> <span class="n">fk_constraint</span><span class="p">[</span><span class="s1">'column'</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="n">ref_column</span> <span class="o">=</span> <span class="n">fk_constraint</span><span class="p">[</span><span class="s1">'referenced_column'</span><span class="p">]</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="bp">self</span><span class="o">.</span><span class="n">infer_relationship_type</span><span class="p">(</span><span class="n">table</span><span class="p">,</span> <span class="n">ref_table</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="sa">f</span><span class="s2">"Creating </span><span class="si">{</span><span class="n">rel_type</span><span class="si">}</span><span class="s2"> relationships: </span><span class="si">{</span><span class="n">table</span><span class="si">}</span><span class="s2"> → </span><span class="si">{</span><span class="n">ref_table</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">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">target</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">table</span><span class="o">.</span><span class="n">title</span><span class="p">()</span><span class="si">}</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">ref_table</span><span class="o">.</span><span class="n">title</span><span class="p">()</span><span class="si">}</span><span class="s2"> </span><span class="se">{{</span><span class="s2">id: a.</span><span class="si">{</span><span class="n">fk_column</span><span class="si">}</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">]->(b)
</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></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="nf">infer_relationship_type</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">from_table</span><span class="p">,</span> <span class="n">to_table</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Infer relationship type from table names."""</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># Simple heuristic - customize for your schema</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="sa">f</span><span class="s2">"HAS_</span><span class="si">{</span><span class="n">to_table</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span><span class="si">}</span><span class="s2">"</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">migrate_join_tables</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">join_table</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Transform many-to-many join tables to relationships."""</span>
</span></span><span class="line"><span class="cl"> <span class="n">left_col</span> <span class="o">=</span> <span class="n">join_table</span><span class="p">[</span><span class="s1">'left_column'</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="n">right_col</span> <span class="o">=</span> <span class="n">join_table</span><span class="p">[</span><span class="s1">'right_column'</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="n">left_entity</span> <span class="o">=</span> <span class="n">join_table</span><span class="p">[</span><span class="s1">'left_entity'</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="n">right_entity</span> <span class="o">=</span> <span class="n">join_table</span><span class="p">[</span><span class="s1">'right_entity'</span><span class="p">]</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="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">left_entity</span><span class="si">}</span><span class="s2">_TO_</span><span class="si">{</span><span class="n">right_entity</span><span class="si">}</span><span class="s2">"</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="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Migrating join table </span><span class="si">{</span><span class="n">join_table</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="n">rel_type</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="n">rows</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">source</span><span class="o">.</span><span class="n">fetch</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"> SELECT * FROM </span><span class="si">{</span><span class="n">join_table</span><span class="p">[</span><span class="s1">'name'</span><span class="p">]</span><span class="si">}</span><span class="s2">
</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></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">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">target</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">left_entity</span><span class="si">}</span><span class="s2"> </span><span class="se">{{</span><span class="s2">id: $left_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">right_entity</span><span class="si">}</span><span class="s2"> </span><span class="se">{{</span><span class="s2">id: $right_id</span><span class="se">}}</span><span class="s2">)
</span></span></span><span class="line"><span class="cl"><span class="s2"> CREATE (a)-[r:</span><span class="si">{</span><span class="n">rel_type</span><span class="si">}</span><span class="s2">]->(b)
</span></span></span><span class="line"><span class="cl"><span class="s2"> SET r = $properties
</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="s1">'left_id'</span><span class="p">:</span> <span class="n">row</span><span class="p">[</span><span class="n">left_col</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'right_id'</span><span class="p">:</span> <span class="n">row</span><span class="p">[</span><span class="n">right_col</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'properties'</span><span class="p">:</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 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">left_col</span><span class="p">,</span> <span class="n">right_col</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"># Example usage</span>
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">migrate_ecommerce_schema</span><span class="p">():</span>
</span></span><span class="line"><span class="cl"> <span class="n">transformer</span> <span class="o">=</span> <span class="n">RelationalToGraphTransformer</span><span class="p">(</span><span class="n">postgres</span><span class="p">,</span> <span class="n">geode</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 entities</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">transformer</span><span class="o">.</span><span class="n">migrate_entities</span><span class="p">(</span><span class="s1">'users'</span><span class="p">,</span> <span class="s1">'User'</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">transformer</span><span class="o">.</span><span class="n">migrate_entities</span><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="k">await</span> <span class="n">transformer</span><span class="o">.</span><span class="n">migrate_entities</span><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></span><span class="line"><span class="cl"> <span class="c1"># Migrate foreign keys</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">transformer</span><span class="o">.</span><span class="n">migrate_foreign_keys</span><span class="p">({</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'table'</span><span class="p">:</span> <span class="s1">'orders'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'referenced_table'</span><span class="p">:</span> <span class="s1">'users'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'column'</span><span class="p">:</span> <span class="s1">'user_id'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'referenced_column'</span><span class="p">:</span> <span class="s1">'id'</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"># Migrate join tables</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">transformer</span><span class="o">.</span><span class="n">migrate_join_tables</span><span class="p">({</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'name'</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="s1">'left_column'</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="s1">'right_column'</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="s1">'left_entity'</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">'right_entity'</span><span class="p">:</span> <span class="s1">'Product'</span>
</span></span><span class="line"><span class="cl"> <span class="p">})</span>
</span></span></code></pre></div>
<h4 id="data-quality-validation" class="position-relative d-flex align-items-center group">
<span>Data Quality 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="data-quality-validation"
aria-haspopup="dialog"
aria-label="Share link: Data Quality 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><p>Comprehensive validation during migration:</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">MigrationValidator</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Validate data quality during and after migration."""</span>
</span></span><span class="line"><span class="cl">
</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">source_db</span><span class="p">,</span> <span class="n">target_graph</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">source</span> <span class="o">=</span> <span class="n">source_db</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">target</span> <span class="o">=</span> <span class="n">target_graph</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">issues</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="k">async</span> <span class="k">def</span> <span class="nf">validate_counts</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">label</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Verify row/node counts match."""</span>
</span></span><span class="line"><span class="cl"> <span class="n">source_count</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">source</span><span class="o">.</span><span class="n">fetch_val</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></span><span class="line"><span class="cl"> <span class="n">result</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">target</span><span class="o">.</span><span class="n">execute</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 count"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">target_count</span> <span class="o">=</span> <span class="p">(</span><span class="n">result</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="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">rows</span> <span class="k">else</span> <span class="kc">None</span><span class="p">)[</span><span class="s1">'count'</span><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="n">source_count</span> <span class="o">!=</span> <span class="n">target_count</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">issues</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">'source'</span><span class="p">:</span> <span class="n">source_count</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'target'</span><span class="p">:</span> <span class="n">target_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="k">return</span> <span class="n">source_count</span> <span class="o">==</span> <span class="n">target_count</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">validate_referential_integrity</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">"""Check for orphaned relationships."""</span>
</span></span><span class="line"><span class="cl"> <span class="n">result</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">target</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"> MATCH ()-[r]->()
</span></span></span><span class="line"><span class="cl"><span class="s2"> WHERE NOT EXISTS {
</span></span></span><span class="line"><span class="cl"><span class="s2"> MATCH (start)-[r]->(end)
</span></span></span><span class="line"><span class="cl"><span class="s2"> WHERE id(start) IS NOT NULL AND id(end) IS NOT NULL
</span></span></span><span class="line"><span class="cl"><span class="s2"> }
</span></span></span><span class="line"><span class="cl"><span class="s2"> RETURN count(r) AS orphaned_relationships
</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></span><span class="line"><span class="cl"> <span class="n">orphaned</span> <span class="o">=</span> <span class="p">(</span><span class="n">result</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="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">rows</span> <span class="k">else</span> <span class="kc">None</span><span class="p">)[</span><span class="s1">'orphaned_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">if</span> <span class="n">orphaned</span> <span class="o">></span> <span class="mi">0</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">issues</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">'orphaned_relationships'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'count'</span><span class="p">:</span> <span class="n">orphaned</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">orphaned</span> <span class="o">==</span> <span class="mi">0</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">validate_data_types</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">property_name</span><span class="p">,</span> <span class="n">expected_type</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Verify property data types."""</span>
</span></span><span class="line"><span class="cl"> <span class="n">result</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">target</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 (n:</span><span class="si">{</span><span class="n">label</span><span class="si">}</span><span class="s2">)
</span></span></span><span class="line"><span class="cl"><span class="s2"> WHERE n.</span><span class="si">{</span><span class="n">property_name</span><span class="si">}</span><span class="s2"> IS NOT NULL
</span></span></span><span class="line"><span class="cl"><span class="s2"> WITH n.</span><span class="si">{</span><span class="n">property_name</span><span class="si">}</span><span class="s2"> AS value, valueType(n.</span><span class="si">{</span><span class="n">property_name</span><span class="si">}</span><span class="s2">) AS actual_type
</span></span></span><span class="line"><span class="cl"><span class="s2"> WHERE actual_type <> $expected_type
</span></span></span><span class="line"><span class="cl"><span class="s2"> RETURN count(*) AS type_mismatches
</span></span></span><span class="line"><span class="cl"><span class="s2"> """</span><span class="p">,</span> <span class="p">{</span><span class="s1">'expected_type'</span><span class="p">:</span> <span class="n">expected_type</span><span class="p">})</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">mismatches</span> <span class="o">=</span> <span class="p">(</span><span class="n">result</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="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">rows</span> <span class="k">else</span> <span class="kc">None</span><span class="p">)[</span><span class="s1">'type_mismatches'</span><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="n">mismatches</span> <span class="o">></span> <span class="mi">0</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">issues</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_type_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">'property'</span><span class="p">:</span> <span class="n">property_name</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'count'</span><span class="p">:</span> <span class="n">mismatches</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">mismatches</span> <span class="o">==</span> <span class="mi">0</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">validate_unique_constraints</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">property_name</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Check for duplicate values in unique properties."""</span>
</span></span><span class="line"><span class="cl"> <span class="n">result</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">target</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 (n:</span><span class="si">{</span><span class="n">label</span><span class="si">}</span><span class="s2">)
</span></span></span><span class="line"><span class="cl"><span class="s2"> WITH n.</span><span class="si">{</span><span class="n">property_name</span><span class="si">}</span><span class="s2"> AS value, count(n) AS occurrences
</span></span></span><span class="line"><span class="cl"><span class="s2"> WHERE occurrences > 1
</span></span></span><span class="line"><span class="cl"><span class="s2"> RETURN count(*) AS duplicates
</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></span><span class="line"><span class="cl"> <span class="n">duplicates</span> <span class="o">=</span> <span class="p">(</span><span class="n">result</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="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">rows</span> <span class="k">else</span> <span class="kc">None</span><span class="p">)[</span><span class="s1">'duplicates'</span><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="n">duplicates</span> <span class="o">></span> <span class="mi">0</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">issues</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">'unique_constraint_violation'</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">'property'</span><span class="p">:</span> <span class="n">property_name</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'count'</span><span class="p">:</span> <span class="n">duplicates</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">duplicates</span> <span class="o">==</span> <span class="mi">0</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">generate_report</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">"""Generate validation report."""</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">issues</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="s2">"✓ All validations passed"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">report</span> <span class="o">=</span> <span class="s2">"Migration Validation Issues:</span><span class="se">\n</span><span class="s2">"</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">issue</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">issues</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">report</span> <span class="o">+=</span> <span class="sa">f</span><span class="s2">"</span><span class="se">\n</span><span class="s2">• </span><span class="si">{</span><span class="n">issue</span><span class="p">[</span><span class="s1">'type'</span><span class="p">]</span><span class="si">}</span><span class="s2">:</span><span class="se">\n</span><span class="s2">"</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">issue</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">key</span> <span class="o">!=</span> <span class="s1">'type'</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">report</span> <span class="o">+=</span> <span class="sa">f</span><span class="s2">" - </span><span class="si">{</span><span class="n">key</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">value</span><span class="si">}</span><span class="se">\n</span><span class="s2">"</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">report</span>
</span></span></code></pre></div>
<h4 id="incremental-migration-with-change-data-capture" class="position-relative d-flex align-items-center group">
<span>Incremental Migration with Change Data Capture</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-with-change-data-capture"
aria-haspopup="dialog"
aria-label="Share link: Incremental Migration with Change Data Capture">
<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">class</span> <span class="nc">CDCMigration</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Migrate data incrementally using change data capture."""</span>
</span></span><span class="line"><span class="cl">
</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">source_db</span><span class="p">,</span> <span class="n">target_graph</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">source</span> <span class="o">=</span> <span class="n">source_db</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">target</span> <span class="o">=</span> <span class="n">target_graph</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">last_sync_timestamp</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">capture_changes</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">since_timestamp</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">"""Capture changes from source database."""</span>
</span></span><span class="line"><span class="cl"> <span class="n">timestamp</span> <span class="o">=</span> <span class="n">since_timestamp</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">last_sync_timestamp</span> <span class="ow">or</span> <span class="s1">'1970-01-01'</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">changes</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">source</span><span class="o">.</span><span class="n">fetch</span><span class="p">(</span><span class="s2">"""
</span></span></span><span class="line"><span class="cl"><span class="s2"> SELECT table_name, operation, record_id, new_data, changed_at
</span></span></span><span class="line"><span class="cl"><span class="s2"> FROM change_log
</span></span></span><span class="line"><span class="cl"><span class="s2"> WHERE changed_at > $timestamp
</span></span></span><span class="line"><span class="cl"><span class="s2"> ORDER BY changed_at
</span></span></span><span class="line"><span class="cl"><span class="s2"> """</span><span class="p">,</span> <span class="p">{</span><span class="s1">'timestamp'</span><span class="p">:</span> <span class="n">timestamp</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">changes</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">apply_changes</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">changes</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Apply changes to target graph database."""</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">change</span> <span class="ow">in</span> <span class="n">changes</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_name'</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">'new_data'</span><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="n">operation</span> <span class="o">==</span> <span class="s1">'INSERT'</span> <span class="ow">or</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="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">target</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"> MERGE (n:</span><span class="si">{</span><span class="n">table</span><span class="o">.</span><span class="n">title</span><span class="p">()</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">)
</span></span></span><span class="line"><span class="cl"><span class="s2"> SET n = $data,
</span></span></span><span class="line"><span class="cl"><span class="s2"> n.synced_at = datetime()
</span></span></span><span class="line"><span class="cl"><span class="s2"> """</span><span class="p">,</span> <span class="p">{</span><span class="s1">'id'</span><span class="p">:</span> <span class="n">change</span><span class="p">[</span><span class="s1">'record_id'</span><span class="p">],</span> <span class="s1">'data'</span><span class="p">:</span> <span class="n">data</span><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="bp">self</span><span class="o">.</span><span class="n">target</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 (n:</span><span class="si">{</span><span class="n">table</span><span class="o">.</span><span class="n">title</span><span class="p">()</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">)
</span></span></span><span class="line"><span class="cl"><span class="s2"> DETACH DELETE n
</span></span></span><span class="line"><span class="cl"><span class="s2"> """</span><span class="p">,</span> <span class="p">{</span><span class="s1">'id'</span><span class="p">:</span> <span class="n">change</span><span class="p">[</span><span class="s1">'record_id'</span><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="n">changes</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">last_sync_timestamp</span> <span class="o">=</span> <span class="n">changes</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="s1">'changed_at'</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">continuous_sync</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">interval_seconds</span><span class="o">=</span><span class="mi">60</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Continuously sync changes."""</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"Starting continuous sync..."</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">while</span> <span class="kc">True</span><span class="p">:</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="n">changes</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">capture_changes</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">changes</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">apply_changes</span><span class="p">(</span><span class="n">changes</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">"Synced </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">changes</span><span class="p">)</span><span class="si">}</span><span class="s2"> changes"</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">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">interval_seconds</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</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="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Sync error: </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 class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">interval_seconds</span><span class="p">)</span>
</span></span></code></pre></div>
<h4 id="migration-rollback-strategy" class="position-relative d-flex align-items-center group">
<span>Migration Rollback Strategy</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-rollback-strategy"
aria-haspopup="dialog"
aria-label="Share link: Migration Rollback Strategy">
<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">class</span> <span class="nc">MigrationRollback</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Provide rollback capability for failed migrations."""</span>
</span></span><span class="line"><span class="cl">
</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">target_graph</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">target</span> <span class="o">=</span> <span class="n">target_graph</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">migration_id</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">checkpoints</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="k">async</span> <span class="k">def</span> <span class="nf">create_checkpoint</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Create a recovery checkpoint."""</span>
</span></span><span class="line"><span class="cl"> <span class="n">checkpoint</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'name'</span><span class="p">:</span> <span class="n">name</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'timestamp'</span><span class="p">:</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'node_count'</span><span class="p">:</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_node_count</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'relationship_count'</span><span class="p">:</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_relationship_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></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">checkpoints</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">checkpoint</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">"Checkpoint created: </span><span class="si">{</span><span class="n">name</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">checkpoint</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">get_node_count</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">"""Get current node count."""</span>
</span></span><span class="line"><span class="cl"> <span class="n">result</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">target</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">"MATCH (n) RETURN count(n) AS count"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">(</span><span class="n">result</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="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">rows</span> <span class="k">else</span> <span class="kc">None</span><span class="p">)[</span><span class="s1">'count'</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">get_relationship_count</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">"""Get current relationship count."""</span>
</span></span><span class="line"><span class="cl"> <span class="n">result</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">target</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">"MATCH ()-[r]->() RETURN count(r) AS count"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">(</span><span class="n">result</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="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">rows</span> <span class="k">else</span> <span class="kc">None</span><span class="p">)[</span><span class="s1">'count'</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">rollback_to_checkpoint</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">checkpoint_name</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Rollback to a specific checkpoint."""</span>
</span></span><span class="line"><span class="cl"> <span class="n">checkpoint</span> <span class="o">=</span> <span class="nb">next</span><span class="p">((</span><span class="n">c</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">checkpoints</span> <span class="k">if</span> <span class="n">c</span><span class="p">[</span><span class="s1">'name'</span><span class="p">]</span> <span class="o">==</span> <span class="n">checkpoint_name</span><span class="p">),</span> <span class="kc">None</span><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="ow">not</span> <span class="n">checkpoint</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Checkpoint not found: </span><span class="si">{</span><span class="n">checkpoint_name</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="sa">f</span><span class="s2">"Rolling back to checkpoint: </span><span class="si">{</span><span class="n">checkpoint_name</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"># Delete nodes created after checkpoint</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">target</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"> MATCH (n)
</span></span></span><span class="line"><span class="cl"><span class="s2"> WHERE n.migrated_at > $checkpoint_time
</span></span></span><span class="line"><span class="cl"><span class="s2"> DETACH DELETE n
</span></span></span><span class="line"><span class="cl"><span class="s2"> """</span><span class="p">,</span> <span class="p">{</span><span class="s1">'checkpoint_time'</span><span class="p">:</span> <span class="n">checkpoint</span><span class="p">[</span><span class="s1">'timestamp'</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">"Rollback 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">## Performance Optimization</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">### Parallel Migration Processing</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">```</span><span class="n">python</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">ParallelMigrator</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Migrate data using parallel workers."""</span>
</span></span><span class="line"><span class="cl">
</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">source_db</span><span class="p">,</span> <span class="n">target_graph</span><span class="p">,</span> <span class="n">num_workers</span><span class="o">=</span><span class="mi">4</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">source</span> <span class="o">=</span> <span class="n">source_db</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">target</span> <span class="o">=</span> <span class="n">target_graph</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">num_workers</span> <span class="o">=</span> <span class="n">num_workers</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">migrate_table_parallel</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">label</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Migrate table using parallel workers."""</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># Get total row count</span>
</span></span><span class="line"><span class="cl"> <span class="n">total_rows</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">source</span><span class="o">.</span><span class="n">fetch_val</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></span><span class="line"><span class="cl"> <span class="n">chunk_size</span> <span class="o">=</span> <span class="n">total_rows</span> <span class="o">//</span> <span class="bp">self</span><span class="o">.</span><span class="n">num_workers</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"># Create worker tasks</span>
</span></span><span class="line"><span class="cl"> <span class="n">tasks</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">worker_id</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">num_workers</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="n">offset</span> <span class="o">=</span> <span class="n">worker_id</span> <span class="o">*</span> <span class="n">chunk_size</span>
</span></span><span class="line"><span class="cl"> <span class="n">task</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">migrate_chunk</span><span class="p">(</span><span class="n">table_name</span><span class="p">,</span> <span class="n">label</span><span class="p">,</span> <span class="n">offset</span><span class="p">,</span> <span class="n">chunk_size</span><span class="p">,</span> <span class="n">worker_id</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">tasks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">task</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Execute in parallel</span>
</span></span><span class="line"><span class="cl"> <span class="n">results</span> <span class="o">=</span> <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">gather</span><span class="p">(</span><span class="o">*</span><span class="n">tasks</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">total_migrated</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span><span class="n">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">"Migrated </span><span class="si">{</span><span class="n">total_migrated</span><span class="si">}</span><span class="s2"> rows 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></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">def</span> <span class="nf">migrate_chunk</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">label</span><span class="p">,</span> <span class="n">offset</span><span class="p">,</span> <span class="n">limit</span><span class="p">,</span> <span class="n">worker_id</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Migrate a chunk of data (worker task)."""</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="bp">self</span><span class="o">.</span><span class="n">source</span><span class="o">.</span><span class="n">fetch</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"> SELECT * FROM </span><span class="si">{</span><span class="n">table_name</span><span class="si">}</span><span class="s2">
</span></span></span><span class="line"><span class="cl"><span class="s2"> ORDER BY id
</span></span></span><span class="line"><span class="cl"><span class="s2"> LIMIT </span><span class="si">{</span><span class="n">limit</span><span class="si">}</span><span class="s2"> OFFSET </span><span class="si">{</span><span class="n">offset</span><span class="si">}</span><span class="s2">
</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></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="ow">not</span> <span class="n">rows</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Create connection for this worker</span>
</span></span><span class="line"><span class="cl"> <span class="n">worker_client</span> <span class="o">=</span> <span class="n">Client</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s2">"localhost"</span><span class="p">,</span> <span class="n">port</span><span class="o">=</span><span class="mi">3141</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">worker_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">begin</span><span class="p">()</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">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"> UNWIND $rows AS row
</span></span></span><span class="line"><span class="cl"><span class="s2"> CREATE (n:</span><span class="si">{</span><span class="n">label</span><span class="si">}</span><span class="s2">)
</span></span></span><span class="line"><span class="cl"><span class="s2"> SET n = row
</span></span></span><span class="line"><span class="cl"><span class="s2"> """</span><span class="p">,</span> <span class="p">{</span><span class="s1">'rows'</span><span class="p">:</span> <span class="n">rows</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="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Worker </span><span class="si">{</span><span class="n">worker_id</span><span class="si">}</span><span class="s2">: Migrated </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">rows</span><span class="p">)</span><span class="si">}</span><span class="s2"> rows"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="n">rows</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">except</span> <span class="ne">Exception</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">rollback</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">raise</span>
</span></span></code></pre></div>
<h3 id="learn-more" class="position-relative d-flex align-items-center group">
<span>Learn More</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="learn-more"
aria-haspopup="dialog"
aria-label="Share link: Learn More">
<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="https://www.liquibase.org/best-practices.html"
aria-label="Database Migration Best Practices – opens in new window"
target="_blank" rel="noopener noreferrer"
>Database Migration Best Practices
<span aria-hidden="true" class="external-icon">↗</span>
</a>
</li>
<li><a
href="https://stripe.com/blog/online-migrations"
aria-label="Zero-Downtime Migrations – opens in new window"
target="_blank" rel="noopener noreferrer"
>Zero-Downtime Migrations
<span aria-hidden="true" class="external-icon">↗</span>
</a>
</li>
</ul>
Related Articles
Guides
20 min
Schema Migration Guide
Plan and execute schema migrations in Geode with zero downtime strategies
Guides
20 min
Data Import Guide
Comprehensive guide to importing data into Geode from various sources
Docs
4 min
Guides
Practical guides for Geode covering backup automation, migration, multi-datacenter deployment, and performance optimization
Docs
9 min
Migration Guide
Comprehensive migration guide for moving data to Geode from other databases, between environments, and across versions
Guides
14 min
Migrating from Neo4j to Geode
Complete guide to migrating from Neo4j to Geode, including Cypher to GQL translation, data export, and driver migration
Guides
19 min
Migrating from PostgreSQL to Geode
Complete guide to migrating from PostgreSQL to Geode, including relational to graph model conversion, ETL pipelines, and incremental migration …
Guides
19 min
Migrating from MongoDB to Geode
Complete guide to migrating from MongoDB to Geode, including document to graph conversion, embedded documents to relationships, and query translation