<!-- CANARY: REQ=REQ-DOCS-001; FEATURE="Docs"; ASPECT=Documentation; STATUS=TESTED; OWNER=docs; UPDATED=2026-01-15 --> <h2 id="data-validation" class="position-relative d-flex align-items-center group"> <span>Data 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-validation" aria-haspopup="dialog" aria-label="Share link: Data 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> </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 validation is the process of ensuring that data conforms to defined rules, formats, and business requirements before it enters or is updated in your Geode graph database. Effective validation prevents data quality issues, maintains referential integrity, and enforces domain-specific constraints across your graph. Geode supports multi-layer validation from database schema constraints to application-level validation logic.</p> <h3 id="why-multi-layer-validation-matters" class="position-relative d-flex align-items-center group"> <span>Why Multi-Layer Validation Matters</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="why-multi-layer-validation-matters" aria-haspopup="dialog" aria-label="Share link: Why Multi-Layer Validation Matters"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h3><p>Relying solely on application-level validation is risky—bugs, API changes, or direct database access can bypass these checks. Conversely, database-only validation can be too rigid for complex business rules. A layered approach provides defense in depth:</p> <ol> <li><strong>Schema Layer</strong>: Type checking, NOT NULL, UNIQUE, CHECK constraints</li> <li><strong>Database Layer</strong>: Custom validation functions, triggers, complex business rules</li> <li><strong>Application Layer</strong>: User experience, async validation, cross-system checks</li> <li><strong>Client Layer</strong>: Immediate feedback, format validation, UX optimization</li> </ol> <h3 id="schema-level-validation" class="position-relative d-flex align-items-center group"> <span>Schema-Level 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="schema-level-validation" aria-haspopup="dialog" aria-label="Share link: Schema-Level 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><p>Schema constraints provide the first and most critical validation layer. These constraints are enforced by Geode at the storage engine level.</p> <h4 id="type-and-format-validation" class="position-relative d-flex align-items-center group"> <span>Type and Format 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="type-and-format-validation" aria-haspopup="dialog" aria-label="Share link: Type and Format 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><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">Basic</span><span class="w"> </span><span class="kd">type</span><span class="w"> </span><span class="nc">and</span><span class="w"> </span><span class="py">format</span><span class="w"> </span><span class="py">validation</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">NODE</span><span class="w"> </span><span class="py">TYPE</span><span class="w"> </span><span class="py">Person</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">email</span><span class="w"> </span><span class="py">STRING</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">email</span><span class="w"> </span><span class="py">LIKE</span><span class="w"> </span><span class="err">&#39;%@%.%&#39;</span><span class="w"> </span><span class="py">AND</span><span class="w"> </span><span class="py">LENGTH</span><span class="p">(</span><span class="py">email</span><span class="p">)</span><span class="w"> </span><span class="err">&lt;</span><span class="p">=</span><span class="w"> </span><span class="py">255</span><span class="p">),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">age</span><span class="w"> </span><span class="py">INTEGER</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">age</span><span class="w"> </span><span class="err">&gt;</span><span class="p">=</span><span class="w"> </span><span class="py">0</span><span class="w"> </span><span class="py">AND</span><span class="w"> </span><span class="py">age</span><span class="w"> </span><span class="err">&lt;</span><span class="p">=</span><span class="w"> </span><span class="py">150</span><span class="p">),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">phone</span><span class="w"> </span><span class="py">STRING</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">phone</span><span class="w"> </span><span class="err">~</span><span class="w"> </span><span class="err">&#39;^\+?</span><span class="p">[</span><span class="py">0</span><span class="err">-</span><span class="py">9</span><span class="p">]{</span><span class="py">10</span><span class="p">,</span><span class="py">15</span><span class="p">}</span><span class="err">$&#39;</span><span class="p">),</span><span class="w"> </span><span class="err">--</span><span class="w"> </span><span class="py">E</span><span class="mf">.164</span><span class="w"> </span><span class="py">format</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">ssn</span><span class="w"> </span><span class="py">STRING</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">ssn</span><span class="w"> </span><span class="err">~</span><span class="w"> </span><span class="err">&#39;^\</span><span class="py">d</span><span class="p">{</span><span class="py">3</span><span class="p">}</span><span class="err">-\</span><span class="py">d</span><span class="p">{</span><span class="py">2</span><span class="p">}</span><span class="err">-\</span><span class="py">d</span><span class="p">{</span><span class="py">4</span><span class="p">}</span><span class="err">$&#39;</span><span class="p">),</span><span class="w"> </span><span class="err">--</span><span class="w"> </span><span class="py">US</span><span class="w"> </span><span class="py">SSN</span><span class="w"> </span><span class="py">format</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">postal_code</span><span class="w"> </span><span class="py">STRING</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">postal_code</span><span class="w"> </span><span class="err">~</span><span class="w"> </span><span class="err">&#39;^</span><span class="p">[</span><span class="py">0</span><span class="err">-</span><span class="py">9</span><span class="p">]{</span><span class="py">5</span><span class="p">}(</span><span class="err">-</span><span class="p">[</span><span class="py">0</span><span class="err">-</span><span class="py">9</span><span class="p">]{</span><span class="py">4</span><span class="p">})</span><span class="err">?$&#39;</span><span class="p">)</span><span class="w"> </span><span class="err">--</span><span class="w"> </span><span class="py">US</span><span class="w"> </span><span class="py">ZIP</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">SKU</span><span class="w"> </span><span class="py">and</span><span class="w"> </span><span class="py">product</span><span class="w"> </span><span class="py">code</span><span class="w"> </span><span class="py">patterns</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">NODE</span><span class="w"> </span><span class="py">TYPE</span><span class="w"> </span><span class="py">Product</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">sku</span><span class="w"> </span><span class="py">STRING</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">sku</span><span class="w"> </span><span class="err">~</span><span class="w"> </span><span class="err">&#39;^</span><span class="p">[</span><span class="py">A</span><span class="err">-</span><span class="py">Z</span><span class="p">]{</span><span class="py">2</span><span class="p">,</span><span class="py">3</span><span class="p">}</span><span class="err">-</span><span class="p">[</span><span class="py">0</span><span class="err">-</span><span class="py">9</span><span class="p">]{</span><span class="py">6</span><span class="p">}</span><span class="err">$&#39;</span><span class="p">),</span><span class="w"> </span><span class="err">--</span><span class="w"> </span><span class="py">Format</span><span class="p">:</span><span class="w"> </span><span class="nc">AB</span><span class="err">-</span><span class="py">123456</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">upc</span><span class="w"> </span><span class="py">STRING</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">upc</span><span class="w"> </span><span class="err">~</span><span class="w"> </span><span class="err">&#39;^\</span><span class="py">d</span><span class="p">{</span><span class="py">12</span><span class="p">}</span><span class="err">$&#39;</span><span class="p">),</span><span class="w"> </span><span class="err">--</span><span class="w"> </span><span class="py">UPC</span><span class="err">-</span><span class="py">A</span><span class="w"> </span><span class="py">barcode</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">price</span><span class="w"> </span><span class="py">DECIMAL</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">price</span><span class="w"> </span><span class="err">&gt;</span><span class="w"> </span><span class="py">0</span><span class="p">),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">weight_kg</span><span class="w"> </span><span class="py">DECIMAL</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">weight_kg</span><span class="w"> </span><span class="err">&gt;</span><span class="w"> </span><span class="py">0</span><span class="w"> </span><span class="py">AND</span><span class="w"> </span><span class="py">weight_kg</span><span class="w"> </span><span class="err">&lt;</span><span class="w"> </span><span class="py">1000</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><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">URL</span><span class="w"> </span><span class="py">and</span><span class="w"> </span><span class="py">domain</span><span class="w"> </span><span class="py">validation</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">NODE</span><span class="w"> </span><span class="py">TYPE</span><span class="w"> </span><span class="py">Website</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">url</span><span class="w"> </span><span class="py">STRING</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">url</span><span class="w"> </span><span class="err">~</span><span class="w"> </span><span class="err">&#39;^</span><span class="py">https</span><span class="err">?</span><span class="p">:</span><span class="err">//</span><span class="p">[</span><span class="nc">a</span><span class="err">-</span><span class="py">zA</span><span class="err">-</span><span class="py">Z0</span><span class="err">-</span><span class="py">9</span><span class="err">.-</span><span class="p">]</span><span class="err">+\.</span><span class="p">[</span><span class="py">a</span><span class="err">-</span><span class="py">z</span><span class="p">]{</span><span class="py">2</span><span class="p">,}(</span><span class="err">/.*</span><span class="p">)</span><span class="err">?$&#39;</span><span class="p">),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">domain</span><span class="w"> </span><span class="py">STRING</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">domain</span><span class="w"> </span><span class="err">~</span><span class="w"> </span><span class="err">&#39;^</span><span class="p">[</span><span class="py">a</span><span class="err">-</span><span class="py">zA</span><span class="err">-</span><span class="py">Z0</span><span class="err">-</span><span class="py">9</span><span class="err">.-</span><span class="p">]</span><span class="err">+\.</span><span class="p">[</span><span class="py">a</span><span class="err">-</span><span class="py">z</span><span class="p">]{</span><span class="py">2</span><span class="p">,}</span><span class="err">$&#39;</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="range-and-enumeration-validation" class="position-relative d-flex align-items-center group"> <span>Range and Enumeration 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="range-and-enumeration-validation" aria-haspopup="dialog" aria-label="Share link: Range and Enumeration 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><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">Numeric</span><span class="w"> </span><span class="py">ranges</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">NODE</span><span class="w"> </span><span class="py">TYPE</span><span class="w"> </span><span class="py">Booking</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">guests</span><span class="w"> </span><span class="py">INTEGER</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">guests</span><span class="w"> </span><span class="err">&gt;</span><span class="p">=</span><span class="w"> </span><span class="py">1</span><span class="w"> </span><span class="py">AND</span><span class="w"> </span><span class="py">guests</span><span class="w"> </span><span class="err">&lt;</span><span class="p">=</span><span class="w"> </span><span class="py">20</span><span class="p">),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">nights</span><span class="w"> </span><span class="py">INTEGER</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">nights</span><span class="w"> </span><span class="err">&gt;</span><span class="p">=</span><span class="w"> </span><span class="py">1</span><span class="w"> </span><span class="py">AND</span><span class="w"> </span><span class="py">nights</span><span class="w"> </span><span class="err">&lt;</span><span class="p">=</span><span class="w"> </span><span class="py">365</span><span class="p">),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">room_number</span><span class="w"> </span><span class="py">INTEGER</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">room_number</span><span class="w"> </span><span class="err">&gt;</span><span class="p">=</span><span class="w"> </span><span class="py">100</span><span class="w"> </span><span class="py">AND</span><span class="w"> </span><span class="py">room_number</span><span class="w"> </span><span class="err">&lt;</span><span class="p">=</span><span class="w"> </span><span class="py">9999</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><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">Enumerated</span><span class="w"> </span><span class="py">values</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">NODE</span><span class="w"> </span><span class="py">TYPE</span><span class="w"> </span><span class="py">Order</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">status</span><span class="w"> </span><span class="py">STRING</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">status</span><span class="w"> </span><span class="py">IN</span><span class="w"> </span><span class="p">(</span><span class="err">&#39;</span><span class="py">draft</span><span class="err">&#39;</span><span class="p">,</span><span class="w"> </span><span class="err">&#39;</span><span class="py">pending</span><span class="err">&#39;</span><span class="p">,</span><span class="w"> </span><span class="err">&#39;</span><span class="py">processing</span><span class="err">&#39;</span><span class="p">,</span><span class="w"> </span><span class="err">&#39;</span><span class="py">shipped</span><span class="err">&#39;</span><span class="p">,</span><span class="w"> </span><span class="err">&#39;</span><span class="py">delivered</span><span class="err">&#39;</span><span class="p">,</span><span class="w"> </span><span class="err">&#39;</span><span class="py">cancelled</span><span class="err">&#39;</span><span class="p">,</span><span class="w"> </span><span class="err">&#39;</span><span class="py">refunded</span><span class="err">&#39;</span><span class="p">)),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">priority</span><span class="w"> </span><span class="py">STRING</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">priority</span><span class="w"> </span><span class="py">IN</span><span class="w"> </span><span class="p">(</span><span class="err">&#39;</span><span class="py">low</span><span class="err">&#39;</span><span class="p">,</span><span class="w"> </span><span class="err">&#39;</span><span class="py">normal</span><span class="err">&#39;</span><span class="p">,</span><span class="w"> </span><span class="err">&#39;</span><span class="py">high</span><span class="err">&#39;</span><span class="p">,</span><span class="w"> </span><span class="err">&#39;</span><span class="py">urgent</span><span class="err">&#39;</span><span class="p">)),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">payment_method</span><span class="w"> </span><span class="py">STRING</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">payment_method</span><span class="w"> </span><span class="py">IN</span><span class="w"> </span><span class="p">(</span><span class="err">&#39;</span><span class="py">credit_card</span><span class="err">&#39;</span><span class="p">,</span><span class="w"> </span><span class="err">&#39;</span><span class="py">debit_card</span><span class="err">&#39;</span><span class="p">,</span><span class="w"> </span><span class="err">&#39;</span><span class="py">paypal</span><span class="err">&#39;</span><span class="p">,</span><span class="w"> </span><span class="err">&#39;</span><span class="py">bank_transfer</span><span class="err">&#39;</span><span class="p">,</span><span class="w"> </span><span class="err">&#39;</span><span class="py">cash</span><span class="err">&#39;</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><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">Percentage</span><span class="w"> </span><span class="py">constraints</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="py">NODE</span><span class="w"> </span><span class="py">TYPE</span><span class="w"> </span><span class="py">Discount</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">percentage</span><span class="w"> </span><span class="py">DECIMAL</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">percentage</span><span class="w"> </span><span class="err">&gt;</span><span class="p">=</span><span class="w"> </span><span class="py">0</span><span class="w"> </span><span class="py">AND</span><span class="w"> </span><span class="py">percentage</span><span class="w"> </span><span class="err">&lt;</span><span class="p">=</span><span class="w"> </span><span class="py">100</span><span class="p">),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">min_order_value</span><span class="w"> </span><span class="py">DECIMAL</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">min_order_value</span><span class="w"> </span><span class="err">&gt;</span><span class="p">=</span><span class="w"> </span><span class="py">0</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="cross-property-validation" class="position-relative d-flex align-items-center group"> <span>Cross-Property 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="cross-property-validation" aria-haspopup="dialog" aria-label="Share link: Cross-Property 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><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">Date</span><span class="w"> </span><span class="py">range</span><span class="w"> </span><span class="py">validation</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">NODE</span><span class="w"> </span><span class="py">TYPE</span><span class="w"> </span><span class="py">Event</span><span class="w"> </span><span class="p">(</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">registration_start</span><span class="w"> </span><span class="py">DATE</span><span class="w"> </span><span class="py">NOT</span><span class="w"> </span><span class="py">NULL</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">registration_end</span><span class="w"> </span><span class="py">DATE</span><span class="w"> </span><span class="py">NOT</span><span class="w"> </span><span class="py">NULL</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">event_start</span><span class="w"> </span><span class="py">DATE</span><span class="w"> </span><span class="py">NOT</span><span class="w"> </span><span class="py">NULL</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">event_end</span><span class="w"> </span><span class="py">DATE</span><span class="w"> </span><span class="py">NOT</span><span class="w"> </span><span class="py">NULL</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">CONSTRAINT</span><span class="w"> </span><span class="py">valid_registration_period</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">registration_end</span><span class="w"> </span><span class="err">&gt;</span><span class="p">=</span><span class="w"> </span><span class="py">registration_start</span><span class="p">),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">CONSTRAINT</span><span class="w"> </span><span class="py">valid_event_period</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">event_end</span><span class="w"> </span><span class="err">&gt;</span><span class="p">=</span><span class="w"> </span><span class="py">event_start</span><span class="p">),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">CONSTRAINT</span><span class="w"> </span><span class="py">registration_before_event</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">registration_end</span><span class="w"> </span><span class="err">&lt;</span><span class="p">=</span><span class="w"> </span><span class="py">event_start</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><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">Conditional</span><span class="w"> </span><span class="py">requirements</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">NODE</span><span class="w"> </span><span class="py">TYPE</span><span class="w"> </span><span class="py">Employee</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">employment_type</span><span class="w"> </span><span class="py">STRING</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">employment_type</span><span class="w"> </span><span class="py">IN</span><span class="w"> </span><span class="p">(</span><span class="err">&#39;</span><span class="py">full_time</span><span class="err">&#39;</span><span class="p">,</span><span class="w"> </span><span class="err">&#39;</span><span class="py">part_time</span><span class="err">&#39;</span><span class="p">,</span><span class="w"> </span><span class="err">&#39;</span><span class="py">contractor</span><span class="err">&#39;</span><span class="p">)),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">annual_salary</span><span class="w"> </span><span class="py">DECIMAL</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">hourly_rate</span><span class="w"> </span><span class="py">DECIMAL</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">benefits_eligible</span><span class="w"> </span><span class="py">BOOLEAN</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">CONSTRAINT</span><span class="w"> </span><span class="py">compensation_model</span><span class="w"> </span><span class="py">CHECK</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="p">(</span><span class="py">employment_type</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="err">&#39;</span><span class="py">full_time</span><span class="err">&#39;</span><span class="w"> </span><span class="py">AND</span><span class="w"> </span><span class="py">annual_salary</span><span class="w"> </span><span class="py">IS</span><span class="w"> </span><span class="py">NOT</span><span class="w"> </span><span class="py">NULL</span><span class="w"> </span><span class="py">AND</span><span class="w"> </span><span class="py">hourly_rate</span><span class="w"> </span><span class="py">IS</span><span class="w"> </span><span class="py">NULL</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></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">(</span><span class="py">employment_type</span><span class="w"> </span><span class="py">IN</span><span class="w"> </span><span class="p">(</span><span class="err">&#39;</span><span class="py">part_time</span><span class="err">&#39;</span><span class="p">,</span><span class="w"> </span><span class="err">&#39;</span><span class="py">contractor</span><span class="err">&#39;</span><span class="p">)</span><span class="w"> </span><span class="py">AND</span><span class="w"> </span><span class="py">annual_salary</span><span class="w"> </span><span class="py">IS</span><span class="w"> </span><span class="py">NULL</span><span class="w"> </span><span class="py">AND</span><span class="w"> </span><span class="py">hourly_rate</span><span class="w"> </span><span class="py">IS</span><span class="w"> </span><span class="py">NOT</span><span class="w"> </span><span class="py">NULL</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">CONSTRAINT</span><span class="w"> </span><span class="py">benefits_eligibility</span><span class="w"> </span><span class="py">CHECK</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">employment_type</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="err">&#39;</span><span class="py">full_time</span><span class="err">&#39;</span><span class="w"> </span><span class="py">OR</span><span class="w"> </span><span class="py">benefits_eligible</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">false</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="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">Price</span><span class="w"> </span><span class="py">consistency</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">NODE</span><span class="w"> </span><span class="py">TYPE</span><span class="w"> </span><span class="py">Product</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">base_price</span><span class="w"> </span><span class="py">DECIMAL</span><span class="w"> </span><span class="py">NOT</span><span class="w"> </span><span class="py">NULL</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">base_price</span><span class="w"> </span><span class="err">&gt;</span><span class="w"> </span><span class="py">0</span><span class="p">),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">sale_price</span><span class="w"> </span><span class="py">DECIMAL</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">sale_price</span><span class="w"> </span><span class="err">&gt;</span><span class="w"> </span><span class="py">0</span><span class="p">),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">cost</span><span class="w"> </span><span class="py">DECIMAL</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">cost</span><span class="w"> </span><span class="err">&gt;</span><span class="w"> </span><span class="py">0</span><span class="p">),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">CONSTRAINT</span><span class="w"> </span><span class="py">sale_below_base</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">sale_price</span><span class="w"> </span><span class="py">IS</span><span class="w"> </span><span class="py">NULL</span><span class="w"> </span><span class="py">OR</span><span class="w"> </span><span class="py">sale_price</span><span class="w"> </span><span class="err">&lt;</span><span class="p">=</span><span class="w"> </span><span class="py">base_price</span><span class="p">),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">CONSTRAINT</span><span class="w"> </span><span class="py">positive_margin</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">base_price</span><span class="w"> </span><span class="err">&gt;</span><span class="w"> </span><span class="py">cost</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> <h3 id="custom-validation-functions" class="position-relative d-flex align-items-center group"> <span>Custom Validation Functions</span> <button type="button" class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1" data-share-target="custom-validation-functions" aria-haspopup="dialog" aria-label="Share link: Custom Validation Functions"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h3><p>Create reusable validation logic as database functions:</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">Email</span><span class="w"> </span><span class="py">validation</span><span class="w"> </span><span class="py">function</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">FUNCTION</span><span class="w"> </span><span class="py">is_valid_email</span><span class="p">(</span><span class="py">email</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">RETURNS</span><span class="w"> </span><span class="py">BOOLEAN</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">AS</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">SELECT</span><span class="w"> </span><span class="py">email</span><span class="w"> </span><span class="py">IS</span><span class="w"> </span><span class="py">NOT</span><span class="w"> </span><span class="py">NULL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">AND</span><span class="w"> </span><span class="py">email</span><span class="w"> </span><span class="err">~</span><span class="w"> </span><span class="err">&#39;^</span><span class="p">[</span><span class="py">a</span><span class="err">-</span><span class="py">zA</span><span class="err">-</span><span class="py">Z0</span><span class="err">-</span><span class="py">9</span><span class="err">.</span><span class="py">_</span><span class="err">%+-</span><span class="p">]</span><span class="err">+@</span><span class="p">[</span><span class="py">a</span><span class="err">-</span><span class="py">zA</span><span class="err">-</span><span class="py">Z0</span><span class="err">-</span><span class="py">9</span><span class="err">.-</span><span class="p">]</span><span class="err">+\.</span><span class="p">[</span><span class="py">a</span><span class="err">-</span><span class="py">zA</span><span class="err">-</span><span class="py">Z</span><span class="p">]{</span><span class="py">2</span><span class="p">,}</span><span class="err">$&#39;</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">LENGTH</span><span class="p">(</span><span class="py">email</span><span class="p">)</span><span class="w"> </span><span class="err">&gt;</span><span class="p">=</span><span class="w"> </span><span class="py">5</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">AND</span><span class="w"> </span><span class="py">LENGTH</span><span class="p">(</span><span class="py">email</span><span class="p">)</span><span class="w"> </span><span class="err">&lt;</span><span class="p">=</span><span class="w"> </span><span class="py">255</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">email</span><span class="w"> </span><span class="py">NOT</span><span class="w"> </span><span class="py">LIKE</span><span class="w"> </span><span class="err">&#39;%@%@%&#39;</span><span class="w"> </span><span class="err">--</span><span class="w"> </span><span class="py">No</span><span class="w"> </span><span class="py">multiple</span><span class="w"> </span><span class="err">@</span><span class="w"> </span><span class="py">signs</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="err">$$;</span><span class="w"> </span></span></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">Phone</span><span class="w"> </span><span class="py">number</span><span class="w"> </span><span class="py">validation</span><span class="w"> </span><span class="p">(</span><span class="py">international</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="py">FUNCTION</span><span class="w"> </span><span class="py">is_valid_phone</span><span class="p">(</span><span class="py">phone</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">RETURNS</span><span class="w"> </span><span class="py">BOOLEAN</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">AS</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">SELECT</span><span class="w"> </span><span class="py">phone</span><span class="w"> </span><span class="err">~</span><span class="w"> </span><span class="err">&#39;^\+?</span><span class="p">[</span><span class="py">1</span><span class="err">-</span><span class="py">9</span><span class="p">]</span><span class="err">\</span><span class="py">d</span><span class="p">{</span><span class="py">1</span><span class="p">,</span><span class="py">14</span><span class="p">}</span><span class="err">$&#39;</span><span class="w"> </span><span class="err">--</span><span class="w"> </span><span class="py">E</span><span class="mf">.164</span><span class="w"> </span><span class="py">format</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="err">$$;</span><span class="w"> </span></span></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">Credit</span><span class="w"> </span><span class="py">card</span><span class="w"> </span><span class="py">validation</span><span class="w"> </span><span class="p">(</span><span class="py">Luhn</span><span class="w"> </span><span class="py">algorithm</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="py">FUNCTION</span><span class="w"> </span><span class="py">is_valid_credit_card</span><span class="p">(</span><span class="py">number</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">RETURNS</span><span class="w"> </span><span class="py">BOOLEAN</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">AS</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="err">--</span><span class="w"> </span><span class="py">Simplified</span><span class="w"> </span><span class="py">Luhn</span><span class="w"> </span><span class="py">check</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">LENGTH</span><span class="p">(</span><span class="py">number</span><span class="p">)</span><span class="w"> </span><span class="py">BETWEEN</span><span class="w"> </span><span class="py">13</span><span class="w"> </span><span class="py">AND</span><span class="w"> </span><span class="py">19</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">number</span><span class="w"> </span><span class="err">~</span><span class="w"> </span><span class="err">&#39;^\</span><span class="py">d</span><span class="err">+$&#39;</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">luhn_checksum</span><span class="p">(</span><span class="py">number</span><span class="p">)</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">0</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="err">$$;</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="err">--</span><span class="w"> </span><span class="py">Use</span><span class="w"> </span><span class="py">in</span><span class="w"> </span><span class="kd">schema</span><span class="w"> </span><span class="py">constraints</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">ALTER</span><span class="w"> </span><span class="py">NODE</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">CONSTRAINT</span><span class="w"> </span><span class="py">check_email</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">is_valid_email</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="py">ALTER</span><span class="w"> </span><span class="py">NODE</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">CONSTRAINT</span><span class="w"> </span><span class="py">check_phone</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">is_valid_phone</span><span class="p">(</span><span class="py">phone</span><span class="p">))</span><span class="err">;</span><span class="w"> </span></span></span></code></pre></div> <h3 id="application-level-validation" class="position-relative d-flex align-items-center group"> <span>Application-Level 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="application-level-validation" aria-haspopup="dialog" aria-label="Share link: Application-Level 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><p>Application-layer validation provides richer error messages, async checks, and user experience optimization.</p> <h4 id="python-validation-with-marshmallow" class="position-relative d-flex align-items-center group"> <span>Python Validation with Marshmallow</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-validation-with-marshmallow" aria-haspopup="dialog" aria-label="Share link: Python Validation with Marshmallow"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">marshmallow</span> <span class="kn">import</span> <span class="n">Schema</span><span class="p">,</span> <span class="n">fields</span><span class="p">,</span> <span class="n">validates</span><span class="p">,</span> <span class="n">validates_schema</span><span class="p">,</span> <span class="n">ValidationError</span> </span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">geode_client</span> <span class="kn">import</span> <span class="n">Client</span> </span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">re</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">PersonSchema</span><span class="p">(</span><span class="n">Schema</span><span class="p">):</span> </span></span><span class="line"><span class="cl"> <span class="n">email</span> <span class="o">=</span> <span class="n">fields</span><span class="o">.</span><span class="n">Email</span><span class="p">(</span><span class="n">required</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">age</span> <span class="o">=</span> <span class="n">fields</span><span class="o">.</span><span class="n">Integer</span><span class="p">(</span><span class="n">required</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">name</span> <span class="o">=</span> <span class="n">fields</span><span class="o">.</span><span class="n">String</span><span class="p">(</span><span class="n">required</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">validate</span><span class="o">=</span><span class="k">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="nb">len</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">phone</span> <span class="o">=</span> <span class="n">fields</span><span class="o">.</span><span class="n">String</span><span class="p">(</span><span class="n">allow_none</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">password</span> <span class="o">=</span> <span class="n">fields</span><span class="o">.</span><span class="n">String</span><span class="p">(</span><span class="n">required</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">load_only</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="nd">@validates</span><span class="p">(</span><span class="s1">&#39;age&#39;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="nf">validate_age</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">value</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">value</span> <span class="o">&gt;</span> <span class="mi">150</span><span class="p">:</span> </span></span><span class="line"><span class="cl"> <span class="k">raise</span> <span class="n">ValidationError</span><span class="p">(</span><span class="s2">&#34;Age must be between 0 and 150&#34;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="nd">@validates</span><span class="p">(</span><span class="s1">&#39;phone&#39;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="nf">validate_phone</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">value</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">re</span><span class="o">.</span><span class="k">match</span><span class="p">(</span><span class="sa">r</span><span class="s1">&#39;^\+?[1-9]\d{1,14}$&#39;</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span> </span></span><span class="line"><span class="cl"> <span class="k">raise</span> <span class="n">ValidationError</span><span class="p">(</span><span class="s2">&#34;Invalid phone number format&#34;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="nd">@validates</span><span class="p">(</span><span class="s1">&#39;password&#39;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="nf">validate_password</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">8</span><span class="p">:</span> </span></span><span class="line"><span class="cl"> <span class="k">raise</span> <span class="n">ValidationError</span><span class="p">(</span><span class="s2">&#34;Password must be at least 8 characters&#34;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="ow">not</span> <span class="n">re</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="sa">r</span><span class="s1">&#39;[A-Z]&#39;</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span> </span></span><span class="line"><span class="cl"> <span class="k">raise</span> <span class="n">ValidationError</span><span class="p">(</span><span class="s2">&#34;Password must contain uppercase letter&#34;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="ow">not</span> <span class="n">re</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="sa">r</span><span class="s1">&#39;[0-9]&#39;</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span> </span></span><span class="line"><span class="cl"> <span class="k">raise</span> <span class="n">ValidationError</span><span class="p">(</span><span class="s2">&#34;Password must contain number&#34;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="nd">@validates_schema</span> </span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="nf">validate_business_rules</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span> </span></span><span class="line"><span class="cl"> <span class="c1"># Cross-field validation</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;age&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">18</span> <span class="ow">and</span> <span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;email&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s1">&#39;.edu&#39;</span><span class="p">):</span> </span></span><span class="line"><span class="cl"> <span class="k">raise</span> <span class="n">ValidationError</span><span class="p">(</span><span class="s2">&#34;Users under 18 cannot use .edu emails&#34;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">create_person</span><span class="p">(</span><span class="n">client</span><span class="p">:</span> <span class="n">Client</span><span class="p">,</span> <span class="n">person_data</span><span class="p">:</span> <span class="nb">dict</span><span class="p">):</span> </span></span><span class="line"><span class="cl"> <span class="s2">&#34;&#34;&#34;Create person with validation.&#34;&#34;&#34;</span> </span></span><span class="line"><span class="cl"> <span class="n">schema</span> <span class="o">=</span> <span class="n">PersonSchema</span><span class="p">()</span> </span></span><span class="line"><span class="cl"> </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="c1"># Validate input data</span> </span></span><span class="line"><span class="cl"> <span class="n">validated</span> <span class="o">=</span> <span class="n">schema</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">person_data</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="k">except</span> <span class="n">ValidationError</span> <span class="k">as</span> <span class="n">err</span><span class="p">:</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">{</span><span class="s2">&#34;success&#34;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span> <span class="s2">&#34;errors&#34;</span><span class="p">:</span> <span class="n">err</span><span class="o">.</span><span class="n">messages</span><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1"># Check uniqueness (async validation)</span> </span></span><span class="line"><span class="cl"> <span class="n">exists</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">query</span><span class="p">(</span> </span></span><span class="line"><span class="cl"> <span class="s2">&#34;MATCH (p:Person {email: $email}) RETURN count(p) AS count&#34;</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s2">&#34;email&#34;</span><span class="p">:</span> <span class="n">validated</span><span class="p">[</span><span class="s1">&#39;email&#39;</span><span class="p">]}</span> </span></span><span class="line"><span class="cl"> <span class="p">)</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">exists</span><span class="o">.</span><span class="n">bindings</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s1">&#39;count&#39;</span><span class="p">]</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">{</span><span class="s2">&#34;success&#34;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span> <span class="s2">&#34;errors&#34;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&#34;email&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;Email already exists&#34;</span><span class="p">]}}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1"># Insert validated data</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">result</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">query</span><span class="p">(</span> </span></span><span class="line"><span class="cl"> <span class="s2">&#34;&#34;&#34;INSERT (p:Person { </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"> name: $name, </span></span></span><span class="line"><span class="cl"><span class="s2"> age: $age, </span></span></span><span class="line"><span class="cl"><span class="s2"> phone: $phone </span></span></span><span class="line"><span class="cl"><span class="s2"> }) RETURN p&#34;&#34;&#34;</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">validated</span> </span></span><span class="line"><span class="cl"> <span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">{</span><span class="s2">&#34;success&#34;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span> <span class="s2">&#34;person&#34;</span><span class="p">:</span> <span class="n">result</span><span class="o">.</span><span class="n">bindings</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s1">&#39;p&#39;</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="k">return</span> <span class="p">{</span><span class="s2">&#34;success&#34;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span> <span class="s2">&#34;errors&#34;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&#34;database&#34;</span><span class="p">:</span> <span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)]}}</span> </span></span></code></pre></div> <h4 id="go-validation-with-validator-library" class="position-relative d-flex align-items-center group"> <span>Go Validation with Validator Library</span> <button type="button" class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1" data-share-target="go-validation-with-validator-library" aria-haspopup="dialog" aria-label="Share link: Go Validation with Validator Library"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span> </span></span><span class="line"><span class="cl"> <span class="s">&#34;context&#34;</span> </span></span><span class="line"><span class="cl"> <span class="s">&#34;fmt&#34;</span> </span></span><span class="line"><span class="cl"> <span class="s">&#34;github.com/go-playground/validator/v10&#34;</span> </span></span><span class="line"><span class="cl"> <span class="s">&#34;geodedb.com/geode&#34;</span> </span></span><span class="line"><span class="cl"><span class="p">)</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Person</span> <span class="kd">struct</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="nx">Email</span> <span class="kt">string</span> <span class="s">`validate:&#34;required,email,max=255&#34;`</span> </span></span><span class="line"><span class="cl"> <span class="nx">Age</span> <span class="kt">int</span> <span class="s">`validate:&#34;required,min=0,max=150&#34;`</span> </span></span><span class="line"><span class="cl"> <span class="nx">Name</span> <span class="kt">string</span> <span class="s">`validate:&#34;required,min=2,max=100&#34;`</span> </span></span><span class="line"><span class="cl"> <span class="nx">Phone</span> <span class="kt">string</span> <span class="s">`validate:&#34;omitempty,e164&#34;`</span> <span class="c1">// E.164 phone format </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">Password</span> <span class="kt">string</span> <span class="s">`validate:&#34;required,min=8,containsany=ABCDEFGHIJKLMNOPQRSTUVWXYZ,containsany=0123456789&#34;`</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">CreatePerson</span><span class="p">(</span><span class="nx">ctx</span> <span class="nx">context</span><span class="p">.</span><span class="nx">Context</span><span class="p">,</span> <span class="nx">db</span> <span class="o">*</span><span class="nx">geode</span><span class="p">.</span><span class="nx">DB</span><span class="p">,</span> <span class="nx">p</span> <span class="o">*</span><span class="nx">Person</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="c1">// Validate struct </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">validate</span> <span class="o">:=</span> <span class="nx">validator</span><span class="p">.</span><span class="nf">New</span><span class="p">()</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">validate</span><span class="p">.</span><span class="nf">Struct</span><span class="p">(</span><span class="nx">p</span><span class="p">);</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="nx">validationErrs</span> <span class="o">:=</span> <span class="nx">err</span><span class="p">.(</span><span class="nx">validator</span><span class="p">.</span><span class="nx">ValidationErrors</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Errorf</span><span class="p">(</span><span class="s">&#34;validation failed: %v&#34;</span><span class="p">,</span> <span class="nx">validationErrs</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">// Check uniqueness </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="kd">var</span> <span class="nx">count</span> <span class="kt">int</span> </span></span><span class="line"><span class="cl"> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">db</span><span class="p">.</span><span class="nf">QueryRowContext</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="s">&#34;MATCH (p:Person {email: $1}) RETURN count(p)&#34;</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="nx">p</span><span class="p">.</span><span class="nx">Email</span><span class="p">).</span><span class="nf">Scan</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">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="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Errorf</span><span class="p">(</span><span class="s">&#34;uniqueness check failed: %w&#34;</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">count</span> <span class="p">&gt;</span> <span class="mi">0</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Errorf</span><span class="p">(</span><span class="s">&#34;email already exists: %s&#34;</span><span class="p">,</span> <span class="nx">p</span><span class="p">.</span><span class="nx">Email</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">// Insert person </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">_</span><span class="p">,</span> <span class="nx">err</span> <span class="p">=</span> <span class="nx">db</span><span class="p">.</span><span class="nf">ExecContext</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="s">`INSERT (p:Person { </span></span></span><span class="line"><span class="cl"><span class="s"> email: $1, </span></span></span><span class="line"><span class="cl"><span class="s"> name: $2, </span></span></span><span class="line"><span class="cl"><span class="s"> age: $3, </span></span></span><span class="line"><span class="cl"><span class="s"> phone: $4 </span></span></span><span class="line"><span class="cl"><span class="s"> })`</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="nx">p</span><span class="p">.</span><span class="nx">Email</span><span class="p">,</span> <span class="nx">p</span><span class="p">.</span><span class="nx">Name</span><span class="p">,</span> <span class="nx">p</span><span class="p">.</span><span class="nx">Age</span><span class="p">,</span> <span class="nx">p</span><span class="p">.</span><span class="nx">Phone</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="nx">err</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div> <h4 id="rust-validation-with-validator-crate" class="position-relative d-flex align-items-center group"> <span>Rust Validation with Validator Crate</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="rust-validation-with-validator-crate" aria-haspopup="dialog" aria-label="Share link: Rust Validation with Validator Crate"> <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-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">validator</span>::<span class="p">{</span><span class="n">Validate</span><span class="p">,</span><span class="w"> </span><span class="n">ValidationError</span><span class="p">};</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">geode_client</span>::<span class="p">{</span><span class="n">Client</span><span class="p">,</span><span class="w"> </span><span class="n">Value</span><span class="p">};</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">collections</span>::<span class="n">HashMap</span><span class="p">;</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="cp">#[derive(Debug, Validate)]</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">struct</span> <span class="nc">Person</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="cp">#[validate(email, length(max = 255))]</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">email</span>: <span class="nb">String</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="cp">#[validate(range(min = 0, max = 150))]</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">age</span>: <span class="kt">i32</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="cp">#[validate(length(min = 2, max = 100))]</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">name</span>: <span class="nb">String</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="cp">#[validate(phone)]</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">phone</span>: <span class="nb">Option</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="cp">#[validate(length(min = 8), custom = </span><span class="s">&#34;validate_password_strength&#34;</span><span class="cp">)]</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">password</span>: <span class="nb">String</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">validate_password_strength</span><span class="p">(</span><span class="n">password</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Result</span><span class="o">&lt;</span><span class="p">(),</span><span class="w"> </span><span class="n">ValidationError</span><span class="o">&gt;</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="kd">let</span><span class="w"> </span><span class="n">has_upper</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">password</span><span class="p">.</span><span class="n">chars</span><span class="p">().</span><span class="n">any</span><span class="p">(</span><span class="o">|</span><span class="n">c</span><span class="o">|</span><span class="w"> </span><span class="n">c</span><span class="p">.</span><span class="n">is_uppercase</span><span class="p">());</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">has_digit</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">password</span><span class="p">.</span><span class="n">chars</span><span class="p">().</span><span class="n">any</span><span class="p">(</span><span class="o">|</span><span class="n">c</span><span class="o">|</span><span class="w"> </span><span class="n">c</span><span class="p">.</span><span class="n">is_numeric</span><span class="p">());</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="o">!</span><span class="n">has_upper</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="o">!</span><span class="n">has_digit</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="n">ValidationError</span>::<span class="n">new</span><span class="p">(</span><span class="s">&#34;password_weak&#34;</span><span class="p">));</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Ok</span><span class="p">(())</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">create_person</span><span class="p">(</span><span class="n">client</span>: <span class="kp">&amp;</span><span class="nc">Client</span><span class="p">,</span><span class="w"> </span><span class="n">person</span>: <span class="kp">&amp;</span><span class="nc">Person</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Result</span><span class="o">&lt;</span><span class="p">(),</span><span class="w"> </span><span class="nb">Box</span><span class="o">&lt;</span><span class="k">dyn</span><span class="w"> </span><span class="n">std</span>::<span class="n">error</span>::<span class="n">Error</span><span class="o">&gt;&gt;</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="c1">// Validate </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w"> </span><span class="n">person</span><span class="p">.</span><span class="n">validate</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="c1">// Check uniqueness </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">params</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">HashMap</span>::<span class="n">new</span><span class="p">();</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">params</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="s">&#34;email&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">Value</span>::<span class="nb">String</span><span class="p">(</span><span class="n">person</span><span class="p">.</span><span class="n">email</span><span class="p">.</span><span class="n">clone</span><span class="p">()));</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">client</span><span class="p">.</span><span class="n">execute</span><span class="p">(</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">&#34;MATCH (p:Person {email: $email}) RETURN count(p) AS count&#34;</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">&amp;</span><span class="n">params</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">).</span><span class="k">await</span><span class="o">?</span><span class="p">;</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">count</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">result</span><span class="p">.</span><span class="n">bindings</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s">&#34;count&#34;</span><span class="p">].</span><span class="n">as_i64</span><span class="p">().</span><span class="n">unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">count</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="s">&#34;Email already exists&#34;</span><span class="p">.</span><span class="n">into</span><span class="p">());</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="c1">// Insert </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">insert_params</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">HashMap</span>::<span class="n">new</span><span class="p">();</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">insert_params</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="s">&#34;email&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">Value</span>::<span class="nb">String</span><span class="p">(</span><span class="n">person</span><span class="p">.</span><span class="n">email</span><span class="p">.</span><span class="n">clone</span><span class="p">()));</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">insert_params</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="s">&#34;name&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">Value</span>::<span class="nb">String</span><span class="p">(</span><span class="n">person</span><span class="p">.</span><span class="n">name</span><span class="p">.</span><span class="n">clone</span><span class="p">()));</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">insert_params</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="s">&#34;age&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">Value</span>::<span class="n">Integer</span><span class="p">(</span><span class="n">person</span><span class="p">.</span><span class="n">age</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">i64</span><span class="p">));</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">client</span><span class="p">.</span><span class="n">execute</span><span class="p">(</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">&#34;INSERT (p:Person {email: $email, name: $name, age: $age})&#34;</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">&amp;</span><span class="n">insert_params</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">).</span><span class="k">await</span><span class="o">?</span><span class="p">;</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Ok</span><span class="p">(())</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w"> </span></span></span></code></pre></div> <h3 id="input-sanitization-and-security" class="position-relative d-flex align-items-center group"> <span>Input Sanitization and Security</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="input-sanitization-and-security" aria-haspopup="dialog" aria-label="Share link: Input Sanitization and Security"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h3><p>Always sanitize user input to prevent injection attacks and data corruption.</p> <h4 id="gql-injection-prevention" class="position-relative d-flex align-items-center group"> <span>GQL Injection Prevention</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="gql-injection-prevention" aria-haspopup="dialog" aria-label="Share link: GQL Injection Prevention"> <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="c1"># NEVER construct queries with string concatenation</span> </span></span><span class="line"><span class="cl"><span class="c1"># BAD - vulnerable to injection</span> </span></span><span class="line"><span class="cl"><span class="n">user_email</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">[</span><span class="s1">&#39;email&#39;</span><span class="p">]</span> </span></span><span class="line"><span class="cl"><span class="n">query</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&#34;MATCH (p:Person </span><span class="se">{{</span><span class="s2">email: &#39;</span><span class="si">{</span><span class="n">user_email</span><span class="si">}</span><span class="s2">&#39;</span><span class="se">}}</span><span class="s2">) RETURN p&#34;</span> <span class="c1"># DANGEROUS!</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="c1"># GOOD - use parameterized queries</span> </span></span><span class="line"><span class="cl"><span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span> </span></span><span class="line"><span class="cl"> <span class="s2">&#34;MATCH (p:Person {email: $email}) RETURN p&#34;</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s2">&#34;email&#34;</span><span class="p">:</span> <span class="n">user_email</span><span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">)</span> </span></span></code></pre></div> <h4 id="xss-prevention" class="position-relative d-flex align-items-center group"> <span>XSS Prevention</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="xss-prevention" aria-haspopup="dialog" aria-label="Share link: XSS Prevention"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">html</span> <span class="kn">import</span> <span class="n">escape</span> </span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">bleach</span> <span class="kn">import</span> <span class="n">clean</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">sanitize_text_input</span><span class="p">(</span><span class="n">text</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span> </span></span><span class="line"><span class="cl"> <span class="s2">&#34;&#34;&#34;Remove HTML and trim whitespace.&#34;&#34;&#34;</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">escape</span><span class="p">(</span><span class="n">text</span><span class="o">.</span><span class="n">strip</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">sanitize_rich_text</span><span class="p">(</span><span class="n">html</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span> </span></span><span class="line"><span class="cl"> <span class="s2">&#34;&#34;&#34;Allow safe HTML tags only.&#34;&#34;&#34;</span> </span></span><span class="line"><span class="cl"> <span class="n">allowed_tags</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;p&#39;</span><span class="p">,</span> <span class="s1">&#39;br&#39;</span><span class="p">,</span> <span class="s1">&#39;strong&#39;</span><span class="p">,</span> <span class="s1">&#39;em&#39;</span><span class="p">,</span> <span class="s1">&#39;ul&#39;</span><span class="p">,</span> <span class="s1">&#39;ol&#39;</span><span class="p">,</span> <span class="s1">&#39;li&#39;</span><span class="p">,</span> <span class="s1">&#39;a&#39;</span><span class="p">]</span> </span></span><span class="line"><span class="cl"> <span class="n">allowed_attrs</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;a&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;href&#39;</span><span class="p">,</span> <span class="s1">&#39;title&#39;</span><span class="p">]}</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">clean</span><span class="p">(</span><span class="n">html</span><span class="p">,</span> <span class="n">tags</span><span class="o">=</span><span class="n">allowed_tags</span><span class="p">,</span> <span class="n">attributes</span><span class="o">=</span><span class="n">allowed_attrs</span><span class="p">,</span> <span class="n">strip</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="c1"># Use in application</span> </span></span><span class="line"><span class="cl"><span class="n">user_bio</span> <span class="o">=</span> <span class="n">sanitize_rich_text</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">[</span><span class="s1">&#39;bio&#39;</span><span class="p">])</span> </span></span><span class="line"><span class="cl"><span class="n">user_name</span> <span class="o">=</span> <span class="n">sanitize_text_input</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">[</span><span class="s1">&#39;name&#39;</span><span class="p">])</span> </span></span></code></pre></div> <h4 id="path-traversal-prevention" class="position-relative d-flex align-items-center group"> <span>Path Traversal Prevention</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="path-traversal-prevention" aria-haspopup="dialog" aria-label="Share link: Path Traversal Prevention"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">os</span> </span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">pathlib</span> <span class="kn">import</span> <span class="n">Path</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">validate_filename</span><span class="p">(</span><span class="n">filename</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span> </span></span><span class="line"><span class="cl"> <span class="s2">&#34;&#34;&#34;Ensure filename is safe and doesn&#39;t contain path traversal.&#34;&#34;&#34;</span> </span></span><span class="line"><span class="cl"> <span class="c1"># Remove directory separators</span> </span></span><span class="line"><span class="cl"> <span class="n">safe_name</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1"># Check for suspicious patterns</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="s1">&#39;..&#39;</span> <span class="ow">in</span> <span class="n">safe_name</span> <span class="ow">or</span> <span class="n">safe_name</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">&#39;.&#39;</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="s2">&#34;Invalid filename&#34;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1"># Limit character set</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="ow">not</span> <span class="nb">all</span><span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">isalnum</span><span class="p">()</span> <span class="ow">or</span> <span class="n">c</span> <span class="ow">in</span> <span class="s1">&#39;.-_&#39;</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">safe_name</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="s2">&#34;Filename contains invalid characters&#34;</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">safe_name</span> </span></span></code></pre></div> <h3 id="validation-error-handling" class="position-relative d-flex align-items-center group"> <span>Validation Error Handling</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-error-handling" aria-haspopup="dialog" aria-label="Share link: Validation Error Handling"> <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="structured-error-responses" class="position-relative d-flex align-items-center group"> <span>Structured Error Responses</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="structured-error-responses" aria-haspopup="dialog" aria-label="Share link: Structured Error Responses"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span><span class="p">,</span> <span class="n">field</span> </span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">List</span><span class="p">,</span> <span class="n">Dict</span><span class="p">,</span> <span class="n">Any</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="nd">@dataclass</span> </span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">ValidationError</span><span class="p">:</span> </span></span><span class="line"><span class="cl"> <span class="n">field</span><span class="p">:</span> <span class="nb">str</span> </span></span><span class="line"><span class="cl"> <span class="n">message</span><span class="p">:</span> <span class="nb">str</span> </span></span><span class="line"><span class="cl"> <span class="n">code</span><span class="p">:</span> <span class="nb">str</span> </span></span><span class="line"><span class="cl"> <span class="n">value</span><span class="p">:</span> <span class="n">Any</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="nd">@dataclass</span> </span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">ValidationResult</span><span class="p">:</span> </span></span><span class="line"><span class="cl"> <span class="n">valid</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span> </span></span><span class="line"><span class="cl"> <span class="n">errors</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">ValidationError</span><span class="p">]</span> <span class="o">=</span> <span class="n">field</span><span class="p">(</span><span class="n">default_factory</span><span class="o">=</span><span class="nb">list</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">warnings</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">ValidationError</span><span class="p">]</span> <span class="o">=</span> <span class="n">field</span><span class="p">(</span><span class="n">default_factory</span><span class="o">=</span><span class="nb">list</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">add_error</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">field</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">code</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&#34;invalid&#34;</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="n">Any</span> <span class="o">=</span> <span class="kc">None</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">valid</span> <span class="o">=</span> <span class="kc">False</span> </span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">errors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ValidationError</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">code</span><span class="p">,</span> <span class="n">value</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">add_warning</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">field</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">code</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&#34;warning&#34;</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">warnings</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ValidationError</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">code</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">to_dict</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="s2">&#34;valid&#34;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">valid</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="s2">&#34;errors&#34;</span><span class="p">:</span> <span class="p">[{</span><span class="s2">&#34;field&#34;</span><span class="p">:</span> <span class="n">e</span><span class="o">.</span><span class="n">field</span><span class="p">,</span> <span class="s2">&#34;message&#34;</span><span class="p">:</span> <span class="n">e</span><span class="o">.</span><span class="n">message</span><span class="p">,</span> <span class="s2">&#34;code&#34;</span><span class="p">:</span> <span class="n">e</span><span class="o">.</span><span class="n">code</span><span class="p">}</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">errors</span><span class="p">],</span> </span></span><span class="line"><span class="cl"> <span class="s2">&#34;warnings&#34;</span><span class="p">:</span> <span class="p">[{</span><span class="s2">&#34;field&#34;</span><span class="p">:</span> <span class="n">w</span><span class="o">.</span><span class="n">field</span><span class="p">,</span> <span class="s2">&#34;message&#34;</span><span class="p">:</span> <span class="n">w</span><span class="o">.</span><span class="n">message</span><span class="p">,</span> <span class="s2">&#34;code&#34;</span><span class="p">:</span> <span class="n">w</span><span class="o">.</span><span class="n">code</span><span class="p">}</span> <span class="k">for</span> <span class="n">w</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">warnings</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></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">validate_order</span><span class="p">(</span><span class="n">order_data</span><span class="p">:</span> <span class="nb">dict</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">ValidationResult</span><span class="p">:</span> </span></span><span class="line"><span class="cl"> <span class="n">result</span> <span class="o">=</span> <span class="n">ValidationResult</span><span class="p">()</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1"># Required fields</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="ow">not</span> <span class="n">order_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;customer_id&#39;</span><span class="p">):</span> </span></span><span class="line"><span class="cl"> <span class="n">result</span><span class="o">.</span><span class="n">add_error</span><span class="p">(</span><span class="s1">&#39;customer_id&#39;</span><span class="p">,</span> <span class="s1">&#39;Customer ID is required&#39;</span><span class="p">,</span> <span class="s1">&#39;required&#39;</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">order_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;items&#39;</span><span class="p">)</span> <span class="ow">or</span> <span class="nb">len</span><span class="p">(</span><span class="n">order_data</span><span class="p">[</span><span class="s1">&#39;items&#39;</span><span class="p">])</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span> </span></span><span class="line"><span class="cl"> <span class="n">result</span><span class="o">.</span><span class="n">add_error</span><span class="p">(</span><span class="s1">&#39;items&#39;</span><span class="p">,</span> <span class="s1">&#39;Order must contain at least one item&#39;</span><span class="p">,</span> <span class="s1">&#39;min_items&#39;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1"># Business rules</span> </span></span><span class="line"><span class="cl"> <span class="n">total</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span><span class="n">item</span><span class="p">[</span><span class="s1">&#39;price&#39;</span><span class="p">]</span> <span class="o">*</span> <span class="n">item</span><span class="p">[</span><span class="s1">&#39;quantity&#39;</span><span class="p">]</span> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">order_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;items&#39;</span><span class="p">,</span> <span class="p">[]))</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">total</span> <span class="o">&lt;</span> <span class="mf">5.00</span><span class="p">:</span> </span></span><span class="line"><span class="cl"> <span class="n">result</span><span class="o">.</span><span class="n">add_warning</span><span class="p">(</span><span class="s1">&#39;total&#39;</span><span class="p">,</span> <span class="sa">f</span><span class="s1">&#39;Order total $</span><span class="si">{</span><span class="n">total</span><span class="si">:</span><span class="s1">.2f</span><span class="si">}</span><span class="s1"> is below minimum $</span><span class="si">{</span><span class="mf">5.00</span><span class="si">}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="s1">&#39;below_minimum&#39;</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">result</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><ol> <li><strong>Validate Early and Often</strong>: Check data at the earliest possible layer</li> <li><strong>Use Schema Constraints</strong>: Enforce data types and ranges at the database level</li> <li><strong>Provide Clear Error Messages</strong>: Users need actionable feedback</li> <li><strong>Sanitize All Input</strong>: Never trust user-provided data</li> <li><strong>Use Parameterized Queries</strong>: Prevent injection attacks</li> <li><strong>Log Validation Failures</strong>: Track patterns of invalid data for improvement</li> <li><strong>Test Validation Logic</strong>: Write unit tests for all validators</li> <li><strong>Document Validation Rules</strong>: Maintain a catalog of business rules</li> <li><strong>Version Validation Rules</strong>: Track changes to validation logic</li> <li><strong>Balance UX and Security</strong>: Validate strictly but provide helpful guidance</li> </ol> <h3 id="common-validation-patterns" class="position-relative d-flex align-items-center group"> <span>Common Validation 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="common-validation-patterns" aria-haspopup="dialog" aria-label="Share link: Common Validation 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><p><strong>Email Uniqueness</strong>:</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">async</span> <span class="k">def</span> <span class="nf">check_email_unique</span><span class="p">(</span><span class="n">email</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span> </span></span><span class="line"><span class="cl"> <span class="n">result</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">query</span><span class="p">(</span> </span></span><span class="line"><span class="cl"> <span class="s2">&#34;MATCH (p:Person {email: $email}) RETURN count(p) AS count&#34;</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s2">&#34;email&#34;</span><span class="p">:</span> <span class="n">email</span><span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">result</span><span class="o">.</span><span class="n">bindings</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s1">&#39;count&#39;</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span> </span></span></code></pre></div><p><strong>Age Verification</strong>:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">EXTRACT</span><span class="p">(</span><span class="py">YEAR</span><span class="w"> </span><span class="py">FROM</span><span class="w"> </span><span class="py">AGE</span><span class="p">(</span><span class="py">CURRENT_DATE</span><span class="p">,</span><span class="w"> </span><span class="py">date_of_birth</span><span class="p">))</span><span class="w"> </span><span class="err">&gt;</span><span class="p">=</span><span class="w"> </span><span class="py">18</span><span class="p">)</span><span class="w"> </span></span></span></code></pre></div><p><strong>Stock Availability</strong>:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="py">CONSTRAINT</span><span class="w"> </span><span class="py">check_stock</span><span class="w"> </span><span class="py">CHECK</span><span class="w"> </span><span class="p">(</span><span class="py">quantity_ordered</span><span class="w"> </span><span class="err">&lt;</span><span class="p">=</span><span class="w"> </span><span class="py">quantity_available</span><span class="p">)</span><span class="w"> </span></span></span></code></pre></div> <h3 id="troubleshooting" class="position-relative d-flex align-items-center group"> <span>Troubleshooting</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="troubleshooting" aria-haspopup="dialog" aria-label="Share link: Troubleshooting"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h3><p><strong>Schema constraint too strict</strong>: Consider if the rule belongs in application layer</p> <p><strong>Performance issues with complex checks</strong>: Move expensive validation to async background jobs</p> <p><strong>Inconsistent validation across clients</strong>: Centralize validation rules in database functions or shared library</p> <p><strong>Users bypassing validation</strong>: Ensure all entry points (API, admin tools, imports) use same validation</p> <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/constraints" >Constraints</a> - Schema-level constraint enforcement</li> <li><a href="/tags/data-quality" >Data Quality</a> - Overall data quality management</li> <li><a href="/tags/security" >Security</a> - Security best practices</li> <li><a href="/tags/security/" >Sanitization</a> - Input sanitization techniques</li> <li><a href="/tags/transactions" >Transactions</a> - Transactional validation</li> <li><a href="/tags/troubleshooting/" >Error Handling</a> - Handling validation errors</li> </ul>

Related Articles

No articles found with this tag yet.

Back to Home