<!-- CANARY: REQ=REQ-DOCS-001; FEATURE="Docs"; ASPECT=Documentation; STATUS=TESTED; OWNER=docs; UPDATED=2026-01-15 --> <h2 id="database-hooks--triggers" class="position-relative d-flex align-items-center group"> <span>Database Hooks &amp;amp; Triggers</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="database-hooks--triggers" aria-haspopup="dialog" aria-label="Share link: Database Hooks &amp;amp; Triggers"> <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>Database hooks and triggers are mechanisms that automatically execute custom logic in response to specific database events. Geode&rsquo;s hooks and triggers enable reactive data management, constraint enforcement, and workflow automation without requiring application-level code.</p> <h3 id="trigger-fundamentals" class="position-relative d-flex align-items-center group"> <span>Trigger Fundamentals</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="trigger-fundamentals" aria-haspopup="dialog" aria-label="Share link: Trigger Fundamentals"> <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="what-are-triggers" class="position-relative d-flex align-items-center group"> <span>What are Triggers?</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="what-are-triggers" aria-haspopup="dialog" aria-label="Share link: What are Triggers?"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Triggers are stored procedures that execute automatically when specific events occur:</p> <p><strong>BEFORE Triggers</strong> - Execute before the operation <strong>AFTER Triggers</strong> - Execute after the operation <strong>INSTEAD OF Triggers</strong> - Replace the original operation</p> <h4 id="trigger-events" class="position-relative d-flex align-items-center group"> <span>Trigger Events</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="trigger-events" aria-haspopup="dialog" aria-label="Share link: Trigger Events"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Triggers respond to DML operations:</p> <ul> <li><strong>INSERT</strong> - New nodes or edges created</li> <li><strong>UPDATE</strong> - Properties modified</li> <li><strong>DELETE</strong> - Nodes or edges removed</li> </ul> <h3 id="creating-triggers" class="position-relative d-flex align-items-center group"> <span>Creating Triggers</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="creating-triggers" aria-haspopup="dialog" aria-label="Share link: Creating Triggers"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h3> <h4 id="basic-trigger-syntax" class="position-relative d-flex align-items-center group"> <span>Basic Trigger Syntax</span> <button type="button" class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1" data-share-target="basic-trigger-syntax" aria-haspopup="dialog" aria-label="Share link: Basic Trigger Syntax"> <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">After</span><span class="w"> </span><span class="py">insert</span><span class="w"> </span><span class="py">trigger</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">TRIGGER</span><span class="w"> </span><span class="py">audit_new_users</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">AFTER</span><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="py">ON</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">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="p">(</span><span class="py">a</span><span class="p">:</span><span class="nc">AuditLog</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">action</span><span class="p">:</span><span class="w"> </span><span class="err">&#39;</span><span class="nc">user_created</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">user_id</span><span class="p">:</span><span class="w"> </span><span class="nc">NEW</span><span class="err">.</span><span class="py">id</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">timestamp</span><span class="p">:</span><span class="w"> </span><span class="nc">NOW</span><span class="p">(),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">details</span><span class="p">:</span><span class="w"> </span><span class="nc">NEW</span><span class="err">.</span><span class="py">properties</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="before-update-trigger" class="position-relative d-flex align-items-center group"> <span>Before Update Trigger</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="before-update-trigger" aria-haspopup="dialog" aria-label="Share link: Before Update Trigger"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Validate or modify data before update:</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">Prevent</span><span class="w"> </span><span class="py">negative</span><span class="w"> </span><span class="py">balance</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">TRIGGER</span><span class="w"> </span><span class="py">check_balance</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">BEFORE</span><span class="w"> </span><span class="py">UPDATE</span><span class="w"> </span><span class="py">ON</span><span class="w"> </span><span class="py">Account</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">WHEN</span><span class="w"> </span><span class="p">(</span><span class="py">NEW</span><span class="err">.</span><span class="py">balance</span><span class="w"> </span><span class="err">&lt;</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">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">SIGNAL</span><span class="w"> </span><span class="err">&#39;</span><span class="py">Insufficient</span><span class="w"> </span><span class="py">funds</span><span class="err">&#39;;</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">Auto</span><span class="err">-</span><span class="py">update</span><span class="w"> </span><span class="py">modification</span><span class="w"> </span><span class="py">time</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">TRIGGER</span><span class="w"> </span><span class="py">update_modified_time</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">BEFORE</span><span class="w"> </span><span class="py">UPDATE</span><span class="w"> </span><span class="py">ON</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">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">SET</span><span class="w"> </span><span class="py">NEW</span><span class="err">.</span><span class="py">modified_at</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">NOW</span><span class="p">()</span><span class="err">;</span><span class="w"> </span></span></span></code></pre></div> <h4 id="after-delete-trigger" class="position-relative d-flex align-items-center group"> <span>After Delete Trigger</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="after-delete-trigger" aria-haspopup="dialog" aria-label="Share link: After Delete Trigger"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Cascade operations after deletion:</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">Archive</span><span class="w"> </span><span class="py">deleted</span><span class="w"> </span><span class="py">users</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">TRIGGER</span><span class="w"> </span><span class="py">archive_deleted_users</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">AFTER</span><span class="w"> </span><span class="py">DELETE</span><span class="w"> </span><span class="py">ON</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">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="p">(</span><span class="py">a</span><span class="p">:</span><span class="nc">ArchivedPerson</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">original_id</span><span class="p">:</span><span class="w"> </span><span class="nc">OLD</span><span class="err">.</span><span class="py">id</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">data</span><span class="p">:</span><span class="w"> </span><span class="nc">OLD</span><span class="err">.</span><span class="py">properties</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">deleted_at</span><span class="p">:</span><span class="w"> </span><span class="nc">NOW</span><span class="p">(),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">deleted_by</span><span class="p">:</span><span class="w"> </span><span class="nc">CURRENT_USER</span><span class="p">()</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">})</span><span class="err">;</span><span class="w"> </span></span></span><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">Clean</span><span class="w"> </span><span class="py">up</span><span class="w"> </span><span class="py">orphaned</span><span class="w"> </span><span class="py">data</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="py">TRIGGER</span><span class="w"> </span><span class="py">cleanup_user_data</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">AFTER</span><span class="w"> </span><span class="py">DELETE</span><span class="w"> </span><span class="py">ON</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">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">DELETE</span><span class="w"> </span><span class="py">FROM</span><span class="w"> </span><span class="py">Post</span><span class="w"> </span><span class="py">WHERE</span><span class="w"> </span><span class="py">author_id</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">OLD</span><span class="err">.</span><span class="py">id</span><span class="err">;</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">DELETE</span><span class="w"> </span><span class="py">FROM</span><span class="w"> </span><span class="py">Comment</span><span class="w"> </span><span class="py">WHERE</span><span class="w"> </span><span class="py">author_id</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">OLD</span><span class="err">.</span><span class="py">id</span><span class="err">;</span><span class="w"> </span></span></span></code></pre></div> <h3 id="hook-types" class="position-relative d-flex align-items-center group"> <span>Hook Types</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="hook-types" aria-haspopup="dialog" aria-label="Share link: Hook Types"> <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="lifecycle-hooks" class="position-relative d-flex align-items-center group"> <span>Lifecycle Hooks</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="lifecycle-hooks" aria-haspopup="dialog" aria-label="Share link: Lifecycle Hooks"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Execute at specific points in entity lifecycle:</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">Before</span><span class="w"> </span><span class="py">creation</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">HOOK</span><span class="w"> </span><span class="py">before_create_person</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">BEFORE</span><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="py">ON</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">EXECUTE</span><span class="w"> </span><span class="py">FUNCTION</span><span class="w"> </span><span class="py">validate_user_data</span><span class="p">(</span><span class="py">NEW</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">After</span><span class="w"> </span><span class="py">creation</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">HOOK</span><span class="w"> </span><span class="py">after_create_person</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">AFTER</span><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="py">ON</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">EXECUTE</span><span class="w"> </span><span class="py">FUNCTION</span><span class="w"> </span><span class="py">send_welcome_email</span><span class="p">(</span><span class="py">NEW</span><span class="err">.</span><span class="py">email</span><span class="p">)</span><span class="err">;</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="err">--</span><span class="w"> </span><span class="py">Before</span><span class="w"> </span><span class="py">update</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">HOOK</span><span class="w"> </span><span class="py">before_update_person</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">BEFORE</span><span class="w"> </span><span class="py">UPDATE</span><span class="w"> </span><span class="py">ON</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">EXECUTE</span><span class="w"> </span><span class="py">FUNCTION</span><span class="w"> </span><span class="py">validate_changes</span><span class="p">(</span><span class="py">OLD</span><span class="p">,</span><span class="w"> </span><span class="py">NEW</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">After</span><span class="w"> </span><span class="py">update</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">HOOK</span><span class="w"> </span><span class="py">after_update_person</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">AFTER</span><span class="w"> </span><span class="py">UPDATE</span><span class="w"> </span><span class="py">ON</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">EXECUTE</span><span class="w"> </span><span class="py">FUNCTION</span><span class="w"> </span><span class="py">notify_profile_change</span><span class="p">(</span><span class="py">NEW</span><span class="p">)</span><span class="err">;</span><span class="w"> </span></span></span></code></pre></div> <h4 id="validation-hooks" class="position-relative d-flex align-items-center group"> <span>Validation Hooks</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-hooks" aria-haspopup="dialog" aria-label="Share link: Validation Hooks"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Enforce business rules:</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">Age</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">TRIGGER</span><span class="w"> </span><span class="py">validate_age</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">BEFORE</span><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="py">OR</span><span class="w"> </span><span class="py">UPDATE</span><span class="w"> </span><span class="py">ON</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">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">WHEN</span><span class="w"> </span><span class="p">(</span><span class="py">NEW</span><span class="err">.</span><span class="py">age</span><span class="w"> </span><span class="err">&lt;</span><span class="w"> </span><span class="py">0</span><span class="w"> </span><span class="py">OR</span><span class="w"> </span><span class="py">NEW</span><span class="err">.</span><span class="py">age</span><span class="w"> </span><span class="err">&gt;</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">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">SIGNAL</span><span class="w"> </span><span class="err">&#39;</span><span class="py">Invalid</span><span class="w"> </span><span class="py">age</span><span class="w"> </span><span class="py">value</span><span class="err">&#39;;</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">Email</span><span class="w"> </span><span class="py">uniqueness</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">TRIGGER</span><span class="w"> </span><span class="py">ensure_unique_email</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">BEFORE</span><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="py">ON</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">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">WHEN</span><span class="w"> </span><span class="py">EXISTS</span><span class="w"> </span><span class="p">(</span><span class="py">SELECT</span><span class="w"> </span><span class="py">1</span><span class="w"> </span><span class="py">FROM</span><span class="w"> </span><span class="py">Person</span><span class="w"> </span><span class="py">WHERE</span><span class="w"> </span><span class="py">email</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">NEW</span><span class="err">.</span><span class="py">email</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">SIGNAL</span><span class="w"> </span><span class="err">&#39;</span><span class="py">Email</span><span class="w"> </span><span class="py">already</span><span class="w"> </span><span class="py">in</span><span class="w"> </span><span class="py">use</span><span class="err">&#39;;</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">Required</span><span class="w"> </span><span class="py">fields</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="py">TRIGGER</span><span class="w"> </span><span class="py">check_required_fields</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">BEFORE</span><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="py">ON</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">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">WHEN</span><span class="w"> </span><span class="p">(</span><span class="py">NEW</span><span class="err">.</span><span class="py">name</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">NEW</span><span class="err">.</span><span class="py">email</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">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">SIGNAL</span><span class="w"> </span><span class="err">&#39;</span><span class="py">Required</span><span class="w"> </span><span class="py">fields</span><span class="w"> </span><span class="py">missing</span><span class="err">&#39;;</span><span class="w"> </span></span></span></code></pre></div> <h4 id="computed-properties" class="position-relative d-flex align-items-center group"> <span>Computed Properties</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="computed-properties" aria-haspopup="dialog" aria-label="Share link: Computed Properties"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Auto-calculate derived values:</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">Full</span><span class="w"> </span><span class="py">name</span><span class="w"> </span><span class="py">from</span><span class="w"> </span><span class="py">first</span><span class="w"> </span><span class="py">and</span><span class="w"> </span><span class="py">last</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">TRIGGER</span><span class="w"> </span><span class="py">compute_full_name</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">BEFORE</span><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="py">OR</span><span class="w"> </span><span class="py">UPDATE</span><span class="w"> </span><span class="py">ON</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">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">SET</span><span class="w"> </span><span class="py">NEW</span><span class="err">.</span><span class="py">full_name</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">NEW</span><span class="err">.</span><span class="py">first_name</span><span class="w"> </span><span class="p">||</span><span class="w"> </span><span class="err">&#39;</span><span class="w"> </span><span class="err">&#39;</span><span class="w"> </span><span class="p">||</span><span class="w"> </span><span class="py">NEW</span><span class="err">.</span><span class="py">last_name</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">Age</span><span class="w"> </span><span class="py">from</span><span class="w"> </span><span class="py">birthdate</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">TRIGGER</span><span class="w"> </span><span class="py">compute_age</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">BEFORE</span><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="py">OR</span><span class="w"> </span><span class="py">UPDATE</span><span class="w"> </span><span class="py">ON</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">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">SET</span><span class="w"> </span><span class="py">NEW</span><span class="err">.</span><span class="py">age</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">YEAR</span><span class="p">(</span><span class="py">NOW</span><span class="p">())</span><span class="w"> </span><span class="err">-</span><span class="w"> </span><span class="py">YEAR</span><span class="p">(</span><span class="py">NEW</span><span class="err">.</span><span class="py">birthdate</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">Order</span><span class="w"> </span><span class="py">total</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">TRIGGER</span><span class="w"> </span><span class="py">compute_order_total</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">BEFORE</span><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="py">OR</span><span class="w"> </span><span class="py">UPDATE</span><span class="w"> </span><span class="py">ON</span><span class="w"> </span><span class="py">Order</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">SET</span><span class="w"> </span><span class="py">NEW</span><span class="err">.</span><span class="py">total</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="p">(</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">SELECT</span><span class="w"> </span><span class="py">SUM</span><span class="p">(</span><span class="py">quantity</span><span class="w"> </span><span class="err">*</span><span class="w"> </span><span class="py">price</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">FROM</span><span class="w"> </span><span class="py">OrderItem</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">WHERE</span><span class="w"> </span><span class="py">order_id</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">NEW</span><span class="err">.</span><span class="py">id</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">)</span><span class="err">;</span><span class="w"> </span></span></span></code></pre></div> <h4 id="audit-logging" class="position-relative d-flex align-items-center group"> <span>Audit Logging</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="audit-logging" aria-haspopup="dialog" aria-label="Share link: Audit Logging"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Track all data changes:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">--</span><span class="w"> </span><span class="py">Comprehensive</span><span class="w"> </span><span class="py">audit</span><span class="w"> </span><span class="py">trail</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">TRIGGER</span><span class="w"> </span><span class="py">audit_all_changes</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">AFTER</span><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="py">OR</span><span class="w"> </span><span class="py">UPDATE</span><span class="w"> </span><span class="py">OR</span><span class="w"> </span><span class="py">DELETE</span><span class="w"> </span><span class="py">ON</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">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="p">(</span><span class="py">log</span><span class="p">:</span><span class="nc">AuditLog</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">table_name</span><span class="p">:</span><span class="w"> </span><span class="err">&#39;</span><span class="nc">Person</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">operation</span><span class="p">:</span><span class="w"> </span><span class="nc">CASE</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">WHEN</span><span class="w"> </span><span class="py">INSERTING</span><span class="w"> </span><span class="py">THEN</span><span class="w"> </span><span class="err">&#39;</span><span class="py">INSERT</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">WHEN</span><span class="w"> </span><span class="py">UPDATING</span><span class="w"> </span><span class="py">THEN</span><span class="w"> </span><span class="err">&#39;</span><span class="py">UPDATE</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">WHEN</span><span class="w"> </span><span class="py">DELETING</span><span class="w"> </span><span class="py">THEN</span><span class="w"> </span><span class="err">&#39;</span><span class="py">DELETE</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">END</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">record_id</span><span class="p">:</span><span class="w"> </span><span class="nc">COALESCE</span><span class="p">(</span><span class="py">NEW</span><span class="err">.</span><span class="py">id</span><span class="p">,</span><span class="w"> </span><span class="py">OLD</span><span class="err">.</span><span class="py">id</span><span class="p">),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">old_value</span><span class="p">:</span><span class="w"> </span><span class="nc">OLD</span><span class="err">.</span><span class="py">properties</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">new_value</span><span class="p">:</span><span class="w"> </span><span class="nc">NEW</span><span class="err">.</span><span class="py">properties</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">changed_by</span><span class="p">:</span><span class="w"> </span><span class="nc">CURRENT_USER</span><span class="p">(),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">changed_at</span><span class="p">:</span><span class="w"> </span><span class="nc">NOW</span><span class="p">(),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">ip_address</span><span class="p">:</span><span class="w"> </span><span class="nc">CURRENT_IP</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="advanced-patterns" class="position-relative d-flex align-items-center group"> <span>Advanced Patterns</span> <button type="button" class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1" data-share-target="advanced-patterns" aria-haspopup="dialog" aria-label="Share link: Advanced Patterns"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h3> <h4 id="conditional-triggers" class="position-relative d-flex align-items-center group"> <span>Conditional Triggers</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="conditional-triggers" aria-haspopup="dialog" aria-label="Share link: Conditional Triggers"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Execute only when conditions met:</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">Only</span><span class="w"> </span><span class="py">trigger</span><span class="w"> </span><span class="py">for</span><span class="w"> </span><span class="py">significant</span><span class="w"> </span><span class="py">changes</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">TRIGGER</span><span class="w"> </span><span class="py">notify_major_update</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">AFTER</span><span class="w"> </span><span class="py">UPDATE</span><span class="w"> </span><span class="py">ON</span><span class="w"> </span><span class="py">Account</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">WHEN</span><span class="w"> </span><span class="p">(</span><span class="py">ABS</span><span class="p">(</span><span class="py">NEW</span><span class="err">.</span><span class="py">balance</span><span class="w"> </span><span class="err">-</span><span class="w"> </span><span class="py">OLD</span><span class="err">.</span><span class="py">balance</span><span class="p">)</span><span class="w"> </span><span class="err">&gt;</span><span class="w"> </span><span class="py">10000</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="p">(</span><span class="py">n</span><span class="p">:</span><span class="nc">Notification</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">type</span><span class="p">:</span><span class="w"> </span><span class="err">&#39;</span><span class="nc">large_transaction</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="nc">account_id</span><span class="p">:</span><span class="w"> </span><span class="nc">NEW</span><span class="err">.</span><span class="py">id</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">old_balance</span><span class="p">:</span><span class="w"> </span><span class="nc">OLD</span><span class="err">.</span><span class="py">balance</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">new_balance</span><span class="p">:</span><span class="w"> </span><span class="nc">NEW</span><span class="err">.</span><span class="py">balance</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">difference</span><span class="p">:</span><span class="w"> </span><span class="nc">NEW</span><span class="err">.</span><span class="py">balance</span><span class="w"> </span><span class="err">-</span><span class="w"> </span><span class="py">OLD</span><span class="err">.</span><span class="py">balance</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">timestamp</span><span class="p">:</span><span class="w"> </span><span class="nc">NOW</span><span class="p">()</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">})</span><span class="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">Status</span><span class="err">-</span><span class="py">based</span><span class="w"> </span><span class="py">triggers</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">TRIGGER</span><span class="w"> </span><span class="py">handle_order_completion</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">AFTER</span><span class="w"> </span><span class="py">UPDATE</span><span class="w"> </span><span class="py">ON</span><span class="w"> </span><span class="py">Order</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">WHEN</span><span class="w"> </span><span class="p">(</span><span class="py">OLD</span><span class="err">.</span><span class="py">status</span><span class="w"> </span><span class="p">!=</span><span class="w"> </span><span class="err">&#39;</span><span class="py">completed</span><span class="err">&#39;</span><span class="w"> </span><span class="py">AND</span><span class="w"> </span><span class="py">NEW</span><span class="err">.</span><span class="py">status</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="err">&#39;</span><span class="py">completed</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">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="p">(</span><span class="py">e</span><span class="p">:</span><span class="nc">Event</span><span class="w"> </span><span class="p">{</span><span class="kd">type</span><span class="p">:</span><span class="w"> </span><span class="err">&#39;</span><span class="nc">order_completed</span><span class="err">&#39;</span><span class="p">,</span><span class="w"> </span><span class="nc">order_id</span><span class="p">:</span><span class="w"> </span><span class="nc">NEW</span><span class="err">.</span><span class="py">id</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 class="py">UPDATE</span><span class="w"> </span><span class="py">Customer</span><span class="w"> </span><span class="py">SET</span><span class="w"> </span><span class="py">total_orders</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">total_orders</span><span class="w"> </span><span class="err">+</span><span class="w"> </span><span class="py">1</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">WHERE</span><span class="w"> </span><span class="py">id</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">NEW</span><span class="err">.</span><span class="py">customer_id</span><span class="err">;</span><span class="w"> </span></span></span></code></pre></div> <h4 id="multi-table-triggers" class="position-relative d-flex align-items-center group"> <span>Multi-Table Triggers</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="multi-table-triggers" aria-haspopup="dialog" aria-label="Share link: Multi-Table Triggers"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Affect multiple tables:</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">Cascade</span><span class="w"> </span><span class="py">inventory</span><span class="w"> </span><span class="py">update</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">TRIGGER</span><span class="w"> </span><span class="py">update_inventory</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">AFTER</span><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="py">ON</span><span class="w"> </span><span class="py">OrderItem</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">UPDATE</span><span class="w"> </span><span class="py">Product</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">SET</span><span class="w"> </span><span class="py">stock_quantity</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">stock_quantity</span><span class="w"> </span><span class="err">-</span><span class="w"> </span><span class="py">NEW</span><span class="err">.</span><span class="py">quantity</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">last_ordered</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">NOW</span><span class="p">()</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">WHERE</span><span class="w"> </span><span class="py">id</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">NEW</span><span class="err">.</span><span class="py">product_id</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">INSERT</span><span class="w"> </span><span class="p">(</span><span class="py">h</span><span class="p">:</span><span class="nc">InventoryHistory</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">product_id</span><span class="p">:</span><span class="w"> </span><span class="nc">NEW</span><span class="err">.</span><span class="py">product_id</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">change</span><span class="p">:</span><span class="w"> </span><span class="err">-</span><span class="nc">NEW</span><span class="err">.</span><span class="py">quantity</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">reason</span><span class="p">:</span><span class="w"> </span><span class="err">&#39;</span><span class="nc">order_placed</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">order_id</span><span class="p">:</span><span class="w"> </span><span class="nc">NEW</span><span class="err">.</span><span class="py">order_id</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">timestamp</span><span class="p">:</span><span class="w"> </span><span class="nc">NOW</span><span class="p">()</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">})</span><span class="err">;</span><span class="w"> </span></span></span></code></pre></div> <h4 id="recursive-triggers" class="position-relative d-flex align-items-center group"> <span>Recursive Triggers</span> <button type="button" class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1" data-share-target="recursive-triggers" aria-haspopup="dialog" aria-label="Share link: Recursive Triggers"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Triggers that may trigger themselves:</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">Set</span><span class="w"> </span><span class="py">recursion</span><span class="w"> </span><span class="py">limit</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">SET</span><span class="w"> </span><span class="py">max_trigger_recursion</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">10</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">Hierarchical</span><span class="w"> </span><span class="py">update</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">TRIGGER</span><span class="w"> </span><span class="py">propagate_category_update</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">AFTER</span><span class="w"> </span><span class="py">UPDATE</span><span class="w"> </span><span class="py">ON</span><span class="w"> </span><span class="py">Category</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">UPDATE</span><span class="w"> </span><span class="py">Category</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">SET</span><span class="w"> </span><span class="py">parent_updated_at</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">NEW</span><span class="err">.</span><span class="py">updated_at</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">WHERE</span><span class="w"> </span><span class="py">parent_id</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">NEW</span><span class="err">.</span><span class="py">id</span><span class="err">;</span><span class="w"> </span></span></span></code></pre></div> <h3 id="trigger-management" class="position-relative d-flex align-items-center group"> <span>Trigger Management</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="trigger-management" aria-haspopup="dialog" aria-label="Share link: Trigger Management"> <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="enablingdisabling-triggers" class="position-relative d-flex align-items-center group"> <span>Enabling/Disabling Triggers</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="enablingdisabling-triggers" aria-haspopup="dialog" aria-label="Share link: Enabling/Disabling Triggers"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Control trigger execution:</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">Disable</span><span class="w"> </span><span class="py">trigger</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">TRIGGER</span><span class="w"> </span><span class="py">audit_new_users</span><span class="w"> </span><span class="py">DISABLE</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">Enable</span><span class="w"> </span><span class="py">trigger</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">TRIGGER</span><span class="w"> </span><span class="py">audit_new_users</span><span class="w"> </span><span class="py">ENABLE</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">Disable</span><span class="w"> </span><span class="py">all</span><span class="w"> </span><span class="py">triggers</span><span class="w"> </span><span class="kd">on</span><span class="w"> </span><span class="py">table</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">ALTER</span><span class="w"> </span><span class="py">TABLE</span><span class="w"> </span><span class="py">Person</span><span class="w"> </span><span class="py">DISABLE</span><span class="w"> </span><span class="py">ALL</span><span class="w"> </span><span class="py">TRIGGERS</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">Enable</span><span class="w"> </span><span class="py">all</span><span class="w"> </span><span class="py">triggers</span><span class="w"> </span><span class="kd">on</span><span class="w"> </span><span class="py">table</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">ALTER</span><span class="w"> </span><span class="py">TABLE</span><span class="w"> </span><span class="py">Person</span><span class="w"> </span><span class="py">ENABLE</span><span class="w"> </span><span class="py">ALL</span><span class="w"> </span><span class="py">TRIGGERS</span><span class="err">;</span><span class="w"> </span></span></span></code></pre></div> <h4 id="dropping-triggers" class="position-relative d-flex align-items-center group"> <span>Dropping Triggers</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="dropping-triggers" aria-haspopup="dialog" aria-label="Share link: Dropping Triggers"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Remove triggers:</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">Drop</span><span class="w"> </span><span class="py">specific</span><span class="w"> </span><span class="py">trigger</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">DROP</span><span class="w"> </span><span class="py">TRIGGER</span><span class="w"> </span><span class="py">IF</span><span class="w"> </span><span class="py">EXISTS</span><span class="w"> </span><span class="py">audit_new_users</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">Drop</span><span class="w"> </span><span class="py">all</span><span class="w"> </span><span class="py">triggers</span><span class="w"> </span><span class="kd">on</span><span class="w"> </span><span class="py">table</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">DROP</span><span class="w"> </span><span class="py">ALL</span><span class="w"> </span><span class="py">TRIGGERS</span><span class="w"> </span><span class="py">ON</span><span class="w"> </span><span class="py">Person</span><span class="err">;</span><span class="w"> </span></span></span></code></pre></div> <h4 id="trigger-inspection" class="position-relative d-flex align-items-center group"> <span>Trigger Inspection</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="trigger-inspection" aria-haspopup="dialog" aria-label="Share link: Trigger Inspection"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Query trigger metadata:</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">List</span><span class="w"> </span><span class="py">all</span><span class="w"> </span><span class="py">triggers</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">trigger_name</span><span class="p">,</span><span class="w"> </span><span class="py">table_name</span><span class="p">,</span><span class="w"> </span><span class="py">event</span><span class="p">,</span><span class="w"> </span><span class="py">timing</span><span class="p">,</span><span class="w"> </span><span class="py">enabled</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">FROM</span><span class="w"> </span><span class="py">SYSTEM</span><span class="err">.</span><span class="py">triggers</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">Get</span><span class="w"> </span><span class="py">trigger</span><span class="w"> </span><span class="py">definition</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">trigger_name</span><span class="p">,</span><span class="w"> </span><span class="py">definition</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">FROM</span><span class="w"> </span><span class="py">SYSTEM</span><span class="err">.</span><span class="py">triggers</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">WHERE</span><span class="w"> </span><span class="py">trigger_name</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="err">&#39;</span><span class="py">audit_new_users</span><span class="err">&#39;;</span><span class="w"> </span></span></span></code></pre></div> <h3 id="performance-considerations" class="position-relative d-flex align-items-center group"> <span>Performance Considerations</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="performance-considerations" aria-haspopup="dialog" aria-label="Share link: Performance Considerations"> <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="trigger-overhead" class="position-relative d-flex align-items-center group"> <span>Trigger Overhead</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="trigger-overhead" aria-haspopup="dialog" aria-label="Share link: Trigger Overhead"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Minimize impact on write performance:</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">Batch</span><span class="w"> </span><span class="py">audit</span><span class="w"> </span><span class="py">logging</span><span class="w"> </span><span class="py">instead</span><span class="w"> </span><span class="py">of</span><span class="w"> </span><span class="py">per</span><span class="err">-</span><span class="py">row</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">TRIGGER</span><span class="w"> </span><span class="py">batch_audit</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">AFTER</span><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="py">ON</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">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">STATEMENT</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="py">INTO</span><span class="w"> </span><span class="py">audit_log</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">SELECT</span><span class="w"> </span><span class="err">&#39;</span><span class="py">INSERT</span><span class="err">&#39;</span><span class="p">,</span><span class="w"> </span><span class="py">NEW</span><span class="err">.</span><span class="py">id</span><span class="p">,</span><span class="w"> </span><span class="py">NEW</span><span class="err">.</span><span class="py">properties</span><span class="p">,</span><span class="w"> </span><span class="py">NOW</span><span class="p">()</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">FROM</span><span class="w"> </span><span class="py">NEW</span><span class="err">;</span><span class="w"> </span></span></span></code></pre></div> <h4 id="async-triggers" class="position-relative d-flex align-items-center group"> <span>Async Triggers</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="async-triggers" aria-haspopup="dialog" aria-label="Share link: Async Triggers"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Defer non-critical work:</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">Queue</span><span class="w"> </span><span class="py">for</span><span class="w"> </span><span class="py">async</span><span class="w"> </span><span class="py">processing</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">TRIGGER</span><span class="w"> </span><span class="py">queue_email</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">AFTER</span><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="py">ON</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">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="py">INTO</span><span class="w"> </span><span class="py">email_queue</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">type</span><span class="p">:</span><span class="w"> </span><span class="err">&#39;</span><span class="nc">welcome</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="nc">recipient</span><span class="p">:</span><span class="w"> </span><span class="nc">NEW</span><span class="err">.</span><span class="py">email</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">data</span><span class="p">:</span><span class="w"> </span><span class="nc">NEW</span><span class="err">.</span><span class="py">properties</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">queued_at</span><span class="p">:</span><span class="w"> </span><span class="nc">NOW</span><span class="p">()</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">)</span><span class="err">;</span><span class="w"> </span></span></span></code></pre></div> <h4 id="trigger-ordering" class="position-relative d-flex align-items-center group"> <span>Trigger Ordering</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="trigger-ordering" aria-haspopup="dialog" aria-label="Share link: Trigger Ordering"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Control execution order:</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">Explicit</span><span class="w"> </span><span class="py">ordering</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">TRIGGER</span><span class="w"> </span><span class="py">validate_first</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">BEFORE</span><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="py">ON</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">ORDER</span><span class="w"> </span><span class="py">1</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span><span class="kd">...</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">CREATE</span><span class="w"> </span><span class="py">TRIGGER</span><span class="w"> </span><span class="py">audit_second</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">BEFORE</span><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="py">ON</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">ORDER</span><span class="w"> </span><span class="py">2</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span><span class="kd">...</span><span class="err">;</span><span class="w"> </span></span></span></code></pre></div> <h3 id="best-practices" class="position-relative d-flex align-items-center group"> <span>Best Practices</span> <button type="button" class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1" data-share-target="best-practices" aria-haspopup="dialog" aria-label="Share link: Best Practices"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h3> <h4 id="trigger-design" class="position-relative d-flex align-items-center group"> <span>Trigger Design</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="trigger-design" aria-haspopup="dialog" aria-label="Share link: Trigger Design"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><ul> <li>Keep triggers simple and focused</li> <li>Avoid complex business logic</li> <li>Document trigger purpose</li> <li>Test thoroughly</li> <li>Monitor performance impact</li> </ul> <h4 id="error-handling" class="position-relative d-flex align-items-center group"> <span>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="error-handling" aria-haspopup="dialog" aria-label="Share link: 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> </h4><ul> <li>Use SIGNAL for validation errors</li> <li>Provide meaningful error messages</li> <li>Log errors for debugging</li> <li>Consider compensation logic</li> </ul> <h4 id="security" class="position-relative d-flex align-items-center group"> <span>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="security" aria-haspopup="dialog" aria-label="Share link: 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> </h4><ul> <li>Validate all inputs</li> <li>Check permissions</li> <li>Prevent SQL injection</li> <li>Audit trigger execution</li> <li>Limit trigger recursion</li> </ul> <h3 id="related-topics" class="position-relative d-flex align-items-center group"> <span>Related Topics</span> <button type="button" class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1" data-share-target="related-topics" aria-haspopup="dialog" aria-label="Share link: Related Topics"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h3><ul> <li><a href="/tags/events" >Events</a> - Event-driven architecture</li> <li><a href="/tags/validation" >Validation</a> - Data validation</li> <li><a href="/tags/constraints" >Constraints</a> - Schema constraints</li> </ul> <h3 id="real-world-hook-implementations" class="position-relative d-flex align-items-center group"> <span>Real-World Hook Implementations</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="real-world-hook-implementations" aria-haspopup="dialog" aria-label="Share link: Real-World Hook Implementations"> <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="multi-tenancy-enforcement" class="position-relative d-flex align-items-center group"> <span>Multi-Tenancy Enforcement</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="multi-tenancy-enforcement" aria-haspopup="dialog" aria-label="Share link: Multi-Tenancy Enforcement"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Automatically add tenant context to all data:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">--</span><span class="w"> </span><span class="py">Inject</span><span class="w"> </span><span class="py">tenant_id</span><span class="w"> </span><span class="kd">on</span><span class="w"> </span><span class="py">all</span><span class="w"> </span><span class="py">creates</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">TRIGGER</span><span class="w"> </span><span class="py">enforce_tenancy</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">BEFORE</span><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="py">ON</span><span class="w"> </span><span class="py">Person</span><span class="p">,</span><span class="w"> </span><span class="py">Company</span><span class="p">,</span><span class="w"> </span><span class="py">Product</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">SET</span><span class="w"> </span><span class="py">NEW</span><span class="err">.</span><span class="py">tenant_id</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">CURRENT_TENANT_ID</span><span class="p">(),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">NEW</span><span class="err">.</span><span class="py">created_by</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">CURRENT_USER</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">Prevent</span><span class="w"> </span><span class="py">cross</span><span class="err">-</span><span class="py">tenant</span><span class="w"> </span><span class="py">access</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">TRIGGER</span><span class="w"> </span><span class="py">validate_tenant_access</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">BEFORE</span><span class="w"> </span><span class="py">UPDATE</span><span class="w"> </span><span class="py">OR</span><span class="w"> </span><span class="py">DELETE</span><span class="w"> </span><span class="py">ON</span><span class="w"> </span><span class="py">Person</span><span class="p">,</span><span class="w"> </span><span class="py">Company</span><span class="p">,</span><span class="w"> </span><span class="py">Product</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">WHEN</span><span class="w"> </span><span class="p">(</span><span class="py">OLD</span><span class="err">.</span><span class="py">tenant_id</span><span class="w"> </span><span class="p">!=</span><span class="w"> </span><span class="py">CURRENT_TENANT_ID</span><span class="p">())</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">SIGNAL</span><span class="w"> </span><span class="err">&#39;</span><span class="py">Access</span><span class="w"> </span><span class="py">denied</span><span class="p">:</span><span class="w"> </span><span class="nc">cross</span><span class="err">-</span><span class="py">tenant</span><span class="w"> </span><span class="py">operation</span><span class="w"> </span><span class="py">not</span><span class="w"> </span><span class="py">allowed</span><span class="err">&#39;;</span><span class="w"> </span></span></span></code></pre></div> <h4 id="data-retention-policy" class="position-relative d-flex align-items-center group"> <span>Data Retention Policy</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-retention-policy" aria-haspopup="dialog" aria-label="Share link: Data Retention Policy"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Automatically archive or delete old data:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">--</span><span class="w"> </span><span class="py">Archive</span><span class="w"> </span><span class="py">records</span><span class="w"> </span><span class="py">older</span><span class="w"> </span><span class="py">than</span><span class="w"> </span><span class="py">7</span><span class="w"> </span><span class="py">years</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">TRIGGER</span><span class="w"> </span><span class="py">enforce_retention_policy</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">AFTER</span><span class="w"> </span><span class="py">UPDATE</span><span class="w"> </span><span class="py">ON</span><span class="w"> </span><span class="py">Event</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">WHEN</span><span class="w"> </span><span class="p">(</span><span class="py">NEW</span><span class="err">.</span><span class="py">timestamp</span><span class="w"> </span><span class="err">&lt;</span><span class="w"> </span><span class="py">datetime</span><span class="p">()</span><span class="err">.</span><span class="py">minusYears</span><span class="p">(</span><span class="py">7</span><span class="p">))</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="err">--</span><span class="w"> </span><span class="py">Move</span><span class="w"> </span><span class="py">to</span><span class="w"> </span><span class="py">archive</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">CREATE</span><span class="w"> </span><span class="p">(</span><span class="py">a</span><span class="p">:</span><span class="nc">ArchivedEvent</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">original_id</span><span class="p">:</span><span class="w"> </span><span class="nc">NEW</span><span class="err">.</span><span class="py">id</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">data</span><span class="p">:</span><span class="w"> </span><span class="nc">NEW</span><span class="err">.</span><span class="py">properties</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">archived_at</span><span class="p">:</span><span class="w"> </span><span class="nc">datetime</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">IN</span><span class="w"> </span><span class="py">GRAPH</span><span class="w"> </span><span class="py">archive_db</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">Delete</span><span class="w"> </span><span class="py">from</span><span class="w"> </span><span class="py">active</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">DELETE</span><span class="w"> </span><span class="py">NEW</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">Schedule</span><span class="w"> </span><span class="py">periodic</span><span class="w"> </span><span class="py">retention</span><span class="w"> </span><span class="py">checks</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">SCHEDULED</span><span class="w"> </span><span class="py">TRIGGER</span><span class="w"> </span><span class="py">retention_cleanup</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EVERY</span><span class="w"> </span><span class="err">&#39;</span><span class="py">1</span><span class="w"> </span><span class="py">day</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">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">e</span><span class="p">:</span><span class="nc">Event</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">WHERE</span><span class="w"> </span><span class="py">e</span><span class="err">.</span><span class="py">timestamp</span><span class="w"> </span><span class="err">&lt;</span><span class="w"> </span><span class="py">datetime</span><span class="p">()</span><span class="err">.</span><span class="py">minusYears</span><span class="p">(</span><span class="py">7</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">WITH</span><span class="w"> </span><span class="py">e</span><span class="w"> </span><span class="py">LIMIT</span><span class="w"> </span><span class="py">1000</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">DELETE</span><span class="w"> </span><span class="py">e</span><span class="err">;</span><span class="w"> </span></span></span></code></pre></div> <h4 id="bi-directional-relationship-sync" class="position-relative d-flex align-items-center group"> <span>Bi-Directional Relationship Sync</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="bi-directional-relationship-sync" aria-haspopup="dialog" aria-label="Share link: Bi-Directional Relationship Sync"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Maintain symmetric relationships:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">--</span><span class="w"> </span><span class="py">When</span><span class="w"> </span><span class="py">A</span><span class="w"> </span><span class="py">friends</span><span class="w"> </span><span class="py">B</span><span class="p">,</span><span class="w"> </span><span class="py">also</span><span class="w"> </span><span class="py">create</span><span class="w"> </span><span class="py">B</span><span class="w"> </span><span class="py">friends</span><span class="w"> </span><span class="py">A</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">TRIGGER</span><span class="w"> </span><span class="py">bidirectional_friendship</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">AFTER</span><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="py">ON</span><span class="w"> </span><span class="p">[:</span><span class="nc">FRIEND</span><span class="p">]</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">RELATIONSHIP</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">WHEN</span><span class="w"> </span><span class="py">NOT</span><span class="w"> </span><span class="py">EXISTS</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">target</span><span class="p">)</span><span class="err">-</span><span class="p">[:</span><span class="nc">FRIEND</span><span class="p">]</span><span class="err">-&gt;</span><span class="p">(</span><span class="py">source</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">WHERE</span><span class="w"> </span><span class="py">source</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">startNode</span><span class="p">(</span><span class="py">NEW</span><span class="p">)</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">target</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">endNode</span><span class="p">(</span><span class="py">NEW</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">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">a</span><span class="p">),</span><span class="w"> </span><span class="p">(</span><span class="py">b</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">WHERE</span><span class="w"> </span><span class="py">id</span><span class="p">(</span><span class="py">a</span><span class="p">)</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">id</span><span class="p">(</span><span class="py">startNode</span><span class="p">(</span><span class="py">NEW</span><span class="p">))</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">id</span><span class="p">(</span><span class="py">b</span><span class="p">)</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">id</span><span class="p">(</span><span class="py">endNode</span><span class="p">(</span><span class="py">NEW</span><span class="p">))</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">CREATE</span><span class="w"> </span><span class="p">(</span><span class="py">b</span><span class="p">)</span><span class="err">-</span><span class="p">[:</span><span class="nc">FRIEND</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">created_at</span><span class="p">:</span><span class="w"> </span><span class="nc">NEW</span><span class="err">.</span><span class="py">created_at</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">bidirectional</span><span class="p">:</span><span class="w"> </span><span class="nc">true</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}]</span><span class="err">-&gt;</span><span class="p">(</span><span class="py">a</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">When</span><span class="w"> </span><span class="py">A</span><span class="w"> </span><span class="py">unfriends</span><span class="w"> </span><span class="py">B</span><span class="p">,</span><span class="w"> </span><span class="py">also</span><span class="w"> </span><span class="py">remove</span><span class="w"> </span><span class="py">B</span><span class="w"> </span><span class="py">friends</span><span class="w"> </span><span class="py">A</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">TRIGGER</span><span class="w"> </span><span class="py">bidirectional_unfriend</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">AFTER</span><span class="w"> </span><span class="py">DELETE</span><span class="w"> </span><span class="py">ON</span><span class="w"> </span><span class="p">[:</span><span class="nc">FRIEND</span><span class="p">]</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">RELATIONSHIP</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">target</span><span class="p">)</span><span class="err">-</span><span class="p">[</span><span class="py">r</span><span class="p">:</span><span class="nc">FRIEND</span><span class="p">]</span><span class="err">-&gt;</span><span class="p">(</span><span class="py">source</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">WHERE</span><span class="w"> </span><span class="py">source</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">startNode</span><span class="p">(</span><span class="py">OLD</span><span class="p">)</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">target</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">endNode</span><span class="p">(</span><span class="py">OLD</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">DELETE</span><span class="w"> </span><span class="py">r</span><span class="err">;</span><span class="w"> </span></span></span></code></pre></div> <h4 id="denormalization-maintenance" class="position-relative d-flex align-items-center group"> <span>Denormalization Maintenance</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="denormalization-maintenance" aria-haspopup="dialog" aria-label="Share link: Denormalization Maintenance"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Keep denormalized data in sync:</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">Update</span><span class="w"> </span><span class="py">user</span><span class="err">&#39;</span><span class="py">s</span><span class="w"> </span><span class="py">post</span><span class="w"> </span><span class="py">count</span><span class="w"> </span><span class="py">when</span><span class="w"> </span><span class="py">posts</span><span class="w"> </span><span class="py">created</span><span class="err">/</span><span class="py">deleted</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">TRIGGER</span><span class="w"> </span><span class="py">maintain_post_count</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">AFTER</span><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="py">OR</span><span class="w"> </span><span class="py">DELETE</span><span class="w"> </span><span class="py">ON</span><span class="w"> </span><span class="py">Post</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">u</span><span class="p">:</span><span class="nc">User</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">COALESCE</span><span class="p">(</span><span class="py">NEW</span><span class="err">.</span><span class="py">author_id</span><span class="p">,</span><span class="w"> </span><span class="py">OLD</span><span class="err">.</span><span class="py">author_id</span><span class="p">)})</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">WITH</span><span class="w"> </span><span class="py">u</span><span class="p">,</span><span class="w"> </span><span class="py">CASE</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">WHEN</span><span class="w"> </span><span class="py">INSERTING</span><span class="w"> </span><span class="py">THEN</span><span class="w"> </span><span class="py">1</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">WHEN</span><span class="w"> </span><span class="py">DELETING</span><span class="w"> </span><span class="py">THEN</span><span class="w"> </span><span class="err">-</span><span class="py">1</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">END</span><span class="w"> </span><span class="py">AS</span><span class="w"> </span><span class="py">delta</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">SET</span><span class="w"> </span><span class="py">u</span><span class="err">.</span><span class="py">post_count</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">u</span><span class="err">.</span><span class="py">post_count</span><span class="w"> </span><span class="err">+</span><span class="w"> </span><span class="py">delta</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">u</span><span class="err">.</span><span class="py">last_post_at</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">CASE</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">WHEN</span><span class="w"> </span><span class="py">INSERTING</span><span class="w"> </span><span class="py">THEN</span><span class="w"> </span><span class="py">datetime</span><span class="p">()</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">ELSE</span><span class="w"> </span><span class="py">u</span><span class="err">.</span><span class="py">last_post_at</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">END</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">Maintain</span><span class="w"> </span><span class="py">aggregated</span><span class="w"> </span><span class="py">statistics</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">TRIGGER</span><span class="w"> </span><span class="py">update_category_stats</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">AFTER</span><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="py">OR</span><span class="w"> </span><span class="py">UPDATE</span><span class="w"> </span><span class="py">OR</span><span class="w"> </span><span class="py">DELETE</span><span class="w"> </span><span class="py">ON</span><span class="w"> </span><span class="py">Product</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">c</span><span class="p">:</span><span class="nc">Category</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">COALESCE</span><span class="p">(</span><span class="py">NEW</span><span class="err">.</span><span class="py">category_id</span><span class="p">,</span><span class="w"> </span><span class="py">OLD</span><span class="err">.</span><span class="py">category_id</span><span class="p">)})</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">WITH</span><span class="w"> </span><span class="py">c</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">COUNT</span><span class="p">{(</span><span class="py">c</span><span class="p">)</span><span class="err">&lt;-</span><span class="p">[:</span><span class="nc">IN_CATEGORY</span><span class="p">]</span><span class="err">-</span><span class="p">(</span><span class="py">p</span><span class="p">:</span><span class="nc">Product</span><span class="p">)}</span><span class="w"> </span><span class="py">AS</span><span class="w"> </span><span class="py">product_count</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">AVG</span><span class="p">{(</span><span class="py">c</span><span class="p">)</span><span class="err">&lt;-</span><span class="p">[:</span><span class="nc">IN_CATEGORY</span><span class="p">]</span><span class="err">-</span><span class="p">(</span><span class="py">p</span><span class="p">:</span><span class="nc">Product</span><span class="p">)</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="py">p</span><span class="err">.</span><span class="py">price</span><span class="p">}</span><span class="w"> </span><span class="py">AS</span><span class="w"> </span><span class="py">avg_price</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">SET</span><span class="w"> </span><span class="py">c</span><span class="err">.</span><span class="py">product_count</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">product_count</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">c</span><span class="err">.</span><span class="py">average_price</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">avg_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">c</span><span class="err">.</span><span class="py">last_updated</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">datetime</span><span class="p">()</span><span class="err">;</span><span class="w"> </span></span></span></code></pre></div> <h4 id="soft-delete-implementation" class="position-relative d-flex align-items-center group"> <span>Soft Delete Implementation</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="soft-delete-implementation" aria-haspopup="dialog" aria-label="Share link: Soft Delete Implementation"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Mark records as deleted instead of removing them:</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">Intercept</span><span class="w"> </span><span class="py">deletes</span><span class="w"> </span><span class="py">and</span><span class="w"> </span><span class="py">convert</span><span class="w"> </span><span class="py">to</span><span class="w"> </span><span class="py">soft</span><span class="w"> </span><span class="py">delete</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">TRIGGER</span><span class="w"> </span><span class="py">soft_delete_user</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">INSTEAD</span><span class="w"> </span><span class="py">OF</span><span class="w"> </span><span class="py">DELETE</span><span class="w"> </span><span class="py">ON</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">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">p</span><span class="p">:</span><span class="nc">Person</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">WHERE</span><span class="w"> </span><span class="py">id</span><span class="p">(</span><span class="py">p</span><span class="p">)</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">id</span><span class="p">(</span><span class="py">OLD</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">SET</span><span class="w"> </span><span class="py">p</span><span class="err">.</span><span class="py">deleted_at</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">datetime</span><span class="p">(),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">p</span><span class="err">.</span><span class="py">deleted_by</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">CURRENT_USER</span><span class="p">(),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">p</span><span class="err">.</span><span class="py">status</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="err">&#39;</span><span class="py">deleted</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">REMOVE</span><span class="w"> </span><span class="py">p</span><span class="p">:</span><span class="nc">Active</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">SET</span><span class="w"> </span><span class="py">p</span><span class="p">:</span><span class="nc">Deleted</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">Hide</span><span class="w"> </span><span class="py">soft</span><span class="err">-</span><span class="py">deleted</span><span class="w"> </span><span class="py">records</span><span class="w"> </span><span class="py">from</span><span class="w"> </span><span class="py">normal</span><span class="w"> </span><span class="py">queries</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="py">VIEW</span><span class="w"> </span><span class="py">ActivePersons</span><span class="w"> </span><span class="py">AS</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">p</span><span class="p">:</span><span class="nc">Person</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">WHERE</span><span class="w"> </span><span class="py">p</span><span class="err">.</span><span class="py">deleted_at</span><span class="w"> </span><span class="py">IS</span><span class="w"> </span><span class="py">NULL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">RETURN</span><span class="w"> </span><span class="py">p</span><span class="err">;</span><span class="w"> </span></span></span></code></pre></div> <h3 id="hook-performance-optimization" class="position-relative d-flex align-items-center group"> <span>Hook Performance Optimization</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="hook-performance-optimization" aria-haspopup="dialog" aria-label="Share link: Hook Performance Optimization"> <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="conditional-execution" class="position-relative d-flex align-items-center group"> <span>Conditional Execution</span> <button type="button" class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1" data-share-target="conditional-execution" aria-haspopup="dialog" aria-label="Share link: Conditional Execution"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Minimize trigger overhead:</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">Only</span><span class="w"> </span><span class="py">execute</span><span class="w"> </span><span class="py">for</span><span class="w"> </span><span class="py">significant</span><span class="w"> </span><span class="py">changes</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">TRIGGER</span><span class="w"> </span><span class="py">notify_price_change</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">AFTER</span><span class="w"> </span><span class="py">UPDATE</span><span class="w"> </span><span class="py">ON</span><span class="w"> </span><span class="py">Product</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">WHEN</span><span class="w"> </span><span class="p">(</span><span class="py">ABS</span><span class="p">(</span><span class="py">NEW</span><span class="err">.</span><span class="py">price</span><span class="w"> </span><span class="err">-</span><span class="w"> </span><span class="py">OLD</span><span class="err">.</span><span class="py">price</span><span class="p">)</span><span class="w"> </span><span class="err">/</span><span class="w"> </span><span class="py">OLD</span><span class="err">.</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="mf">.1</span><span class="p">)</span><span class="w"> </span><span class="err">--</span><span class="w"> </span><span class="err">&gt;</span><span class="py">10</span><span class="err">%</span><span class="w"> </span><span class="py">change</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">CREATE</span><span class="w"> </span><span class="p">(</span><span class="py">n</span><span class="p">:</span><span class="nc">PriceChangeNotification</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">product_id</span><span class="p">:</span><span class="w"> </span><span class="nc">NEW</span><span class="err">.</span><span class="py">id</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">old_price</span><span class="p">:</span><span class="w"> </span><span class="nc">OLD</span><span class="err">.</span><span class="py">price</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">new_price</span><span class="p">:</span><span class="w"> </span><span class="nc">NEW</span><span class="err">.</span><span class="py">price</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">change_percent</span><span class="p">:</span><span class="w"> </span><span class="p">(</span><span class="nc">NEW</span><span class="err">.</span><span class="py">price</span><span class="w"> </span><span class="err">-</span><span class="w"> </span><span class="py">OLD</span><span class="err">.</span><span class="py">price</span><span class="p">)</span><span class="w"> </span><span class="err">/</span><span class="w"> </span><span class="py">OLD</span><span class="err">.</span><span class="py">price</span><span class="w"> </span><span class="err">*</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">timestamp</span><span class="p">:</span><span class="w"> </span><span class="nc">datetime</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="batching-hook-actions" class="position-relative d-flex align-items-center group"> <span>Batching Hook Actions</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="batching-hook-actions" aria-haspopup="dialog" aria-label="Share link: Batching Hook Actions"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Process multiple rows efficiently:</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">Per</span><span class="err">-</span><span class="py">statement</span><span class="w"> </span><span class="py">trigger</span><span class="w"> </span><span class="p">(</span><span class="py">not</span><span class="w"> </span><span class="py">per</span><span class="err">-</span><span class="py">row</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">TRIGGER</span><span class="w"> </span><span class="py">batch_audit_inserts</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">AFTER</span><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="py">ON</span><span class="w"> </span><span class="py">User</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">STATEMENT</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="err">--</span><span class="w"> </span><span class="py">NEW</span><span class="w"> </span><span class="py">represents</span><span class="w"> </span><span class="py">all</span><span class="w"> </span><span class="py">inserted</span><span class="w"> </span><span class="py">rows</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">WITH</span><span class="w"> </span><span class="py">NEW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">UNWIND</span><span class="w"> </span><span class="py">NEW</span><span class="w"> </span><span class="py">AS</span><span class="w"> </span><span class="py">user</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">CREATE</span><span class="w"> </span><span class="p">(</span><span class="py">a</span><span class="p">:</span><span class="nc">AuditLog</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">action</span><span class="p">:</span><span class="w"> </span><span class="err">&#39;</span><span class="nc">user_created</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">user_ids</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="nc">u</span><span class="w"> </span><span class="py">IN</span><span class="w"> </span><span class="py">NEW</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="py">u</span><span class="err">.</span><span class="py">id</span><span class="p">],</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">count</span><span class="p">:</span><span class="w"> </span><span class="nc">SIZE</span><span class="p">(</span><span class="py">NEW</span><span class="p">),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">timestamp</span><span class="p">:</span><span class="w"> </span><span class="nc">datetime</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="async-hook-execution" class="position-relative d-flex align-items-center group"> <span>Async Hook Execution</span> <button type="button" class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1" data-share-target="async-hook-execution" aria-haspopup="dialog" aria-label="Share link: Async Hook Execution"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Defer non-critical work:</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">Queue</span><span class="w"> </span><span class="py">for</span><span class="w"> </span><span class="py">async</span><span class="w"> </span><span class="py">processing</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">TRIGGER</span><span class="w"> </span><span class="py">queue_welcome_email</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">AFTER</span><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="py">ON</span><span class="w"> </span><span class="py">User</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">CREATE</span><span class="w"> </span><span class="p">(</span><span class="py">job</span><span class="p">:</span><span class="nc">AsyncJob</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">type</span><span class="p">:</span><span class="w"> </span><span class="err">&#39;</span><span class="nc">send_welcome_email</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="nc">user_id</span><span class="p">:</span><span class="w"> </span><span class="nc">NEW</span><span class="err">.</span><span class="py">id</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">user_email</span><span class="p">:</span><span class="w"> </span><span class="nc">NEW</span><span class="err">.</span><span class="py">email</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">queued_at</span><span class="p">:</span><span class="w"> </span><span class="nc">datetime</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="p">:</span><span class="w"> </span><span class="err">&#39;</span><span class="nc">pending</span><span class="err">&#39;</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">Background</span><span class="w"> </span><span class="py">worker</span><span class="w"> </span><span class="py">processes</span><span class="w"> </span><span class="py">jobs</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="p">(</span><span class="py">separate</span><span class="w"> </span><span class="py">process</span><span class="p">,</span><span class="w"> </span><span class="py">no</span><span class="w"> </span><span class="py">blocking</span><span class="w"> </span><span class="kd">on</span><span class="w"> </span><span class="py">insert</span><span class="p">)</span><span class="w"> </span></span></span></code></pre></div> <h3 id="hook-testing-strategies" class="position-relative d-flex align-items-center group"> <span>Hook Testing Strategies</span> <button type="button" class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1" data-share-target="hook-testing-strategies" aria-haspopup="dialog" aria-label="Share link: Hook Testing Strategies"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h3> <h4 id="unit-testing-hooks" class="position-relative d-flex align-items-center group"> <span>Unit Testing Hooks</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="unit-testing-hooks" aria-haspopup="dialog" aria-label="Share link: Unit Testing Hooks"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Test trigger logic in isolation:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">pytest</span> </span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">geode_client</span> <span class="kn">import</span> <span class="n">Client</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="nd">@pytest.fixture</span> </span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">client</span><span class="p">():</span> </span></span><span class="line"><span class="cl"> <span class="n">client</span> <span class="o">=</span> <span class="k">await</span> <span class="n">Client</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s2">&#34;localhost:3141&#34;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="k">yield</span> <span class="n">client</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">close</span><span class="p">()</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="nd">@pytest.mark.asyncio</span> </span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">test_audit_trigger</span><span class="p">(</span><span class="n">client</span><span class="p">):</span> </span></span><span class="line"><span class="cl"> <span class="s2">&#34;&#34;&#34;Test audit log trigger creates entries&#34;&#34;&#34;</span> </span></span><span class="line"><span class="cl"> <span class="c1"># Insert user (triggers audit hook)</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 class="s2">&#34;&#34;&#34; </span></span></span><span class="line"><span class="cl"><span class="s2"> CREATE (:User {id: 123, name: &#39;Test User&#39;, email: &#39;[email protected]&#39;}) </span></span></span><span class="line"><span class="cl"><span class="s2"> &#34;&#34;&#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"># Verify audit log created</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 class="s2">&#34;&#34;&#34; </span></span></span><span class="line"><span class="cl"><span class="s2"> MATCH (a:AuditLog) </span></span></span><span class="line"><span class="cl"><span class="s2"> WHERE a.action = &#39;user_created&#39; </span></span></span><span class="line"><span class="cl"><span class="s2"> AND a.record_id = 123 </span></span></span><span class="line"><span class="cl"><span class="s2"> RETURN a </span></span></span><span class="line"><span class="cl"><span class="s2"> &#34;&#34;&#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">assert</span> <span class="nb">len</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="o">==</span> <span class="mi">1</span> </span></span><span class="line"><span class="cl"> <span class="n">audit</span> <span class="o">=</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;a&#39;</span><span class="p">]</span> </span></span><span class="line"><span class="cl"> <span class="k">assert</span> <span class="n">audit</span><span class="p">[</span><span class="s1">&#39;action&#39;</span><span class="p">]</span> <span class="o">==</span> <span class="s1">&#39;user_created&#39;</span> </span></span><span class="line"><span class="cl"> <span class="k">assert</span> <span class="s1">&#39;[email protected]&#39;</span> <span class="ow">in</span> <span class="n">audit</span><span class="p">[</span><span class="s1">&#39;details&#39;</span><span class="p">]</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="nd">@pytest.mark.asyncio</span> </span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">test_validation_trigger</span><span class="p">(</span><span class="n">client</span><span class="p">):</span> </span></span><span class="line"><span class="cl"> <span class="s2">&#34;&#34;&#34;Test validation trigger rejects invalid data&#34;&#34;&#34;</span> </span></span><span class="line"><span class="cl"> <span class="k">with</span> <span class="n">pytest</span><span class="o">.</span><span class="n">raises</span><span class="p">(</span><span class="ne">Exception</span><span class="p">,</span> <span class="k">match</span><span class="o">=</span><span class="s2">&#34;Invalid age value&#34;</span><span class="p">):</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 class="s2">&#34;&#34;&#34; </span></span></span><span class="line"><span class="cl"><span class="s2"> CREATE (:Person {id: 456, name: &#39;Invalid&#39;, age: -5}) </span></span></span><span class="line"><span class="cl"><span class="s2"> &#34;&#34;&#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"># Verify no record created</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 class="s2">&#34;&#34;&#34; </span></span></span><span class="line"><span class="cl"><span class="s2"> MATCH (p:Person </span><span class="si">{id: 456}</span><span class="s2">) RETURN p </span></span></span><span class="line"><span class="cl"><span class="s2"> &#34;&#34;&#34;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="k">assert</span> <span class="nb">len</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="o">==</span> <span class="mi">0</span> </span></span></code></pre></div> <h4 id="integration-testing" class="position-relative d-flex align-items-center group"> <span>Integration Testing</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="integration-testing" aria-haspopup="dialog" aria-label="Share link: Integration Testing"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Test hooks with full workflows:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="nd">@pytest.mark.asyncio</span> </span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">test_bidirectional_friendship</span><span class="p">(</span><span class="n">client</span><span class="p">):</span> </span></span><span class="line"><span class="cl"> <span class="s2">&#34;&#34;&#34;Test bidirectional friendship trigger&#34;&#34;&#34;</span> </span></span><span class="line"><span class="cl"> <span class="c1"># Create users</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 class="s2">&#34;&#34;&#34; </span></span></span><span class="line"><span class="cl"><span class="s2"> CREATE (:User {id: 1, name: &#39;Alice&#39;}) </span></span></span><span class="line"><span class="cl"><span class="s2"> CREATE (:User {id: 2, name: &#39;Bob&#39;}) </span></span></span><span class="line"><span class="cl"><span class="s2"> &#34;&#34;&#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"># Create friendship (triggers bidirectional hook)</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 class="s2">&#34;&#34;&#34; </span></span></span><span class="line"><span class="cl"><span class="s2"> MATCH (a:User </span><span class="si">{id: 1}</span><span class="s2">), (b:User </span><span class="si">{id: 2}</span><span class="s2">) </span></span></span><span class="line"><span class="cl"><span class="s2"> CREATE (a)-[:FRIEND {created_at: datetime()}]-&gt;(b) </span></span></span><span class="line"><span class="cl"><span class="s2"> &#34;&#34;&#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"># Verify both directions exist</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 class="s2">&#34;&#34;&#34; </span></span></span><span class="line"><span class="cl"><span class="s2"> MATCH (a:User </span><span class="si">{id: 1}</span><span class="s2">)-[:FRIEND]-&gt;(b:User </span><span class="si">{id: 2}</span><span class="s2">), </span></span></span><span class="line"><span class="cl"><span class="s2"> (b)-[:FRIEND]-&gt;(a) </span></span></span><span class="line"><span class="cl"><span class="s2"> RETURN a.name, b.name </span></span></span><span class="line"><span class="cl"><span class="s2"> &#34;&#34;&#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">assert</span> <span class="nb">len</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="o">==</span> <span class="mi">1</span> </span></span></code></pre></div> <h3 id="debugging-hooks" class="position-relative d-flex align-items-center group"> <span>Debugging Hooks</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="debugging-hooks" aria-haspopup="dialog" aria-label="Share link: Debugging Hooks"> <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="trigger-execution-log" class="position-relative d-flex align-items-center group"> <span>Trigger Execution Log</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="trigger-execution-log" aria-haspopup="dialog" aria-label="Share link: Trigger Execution Log"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Track trigger executions:</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">Enable</span><span class="w"> </span><span class="py">trigger</span><span class="w"> </span><span class="py">logging</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">SET</span><span class="w"> </span><span class="py">trigger_logging</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">true</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">Execute</span><span class="w"> </span><span class="py">operation</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">CREATE</span><span class="w"> </span><span class="p">(:</span><span class="nc">User</span><span class="w"> </span><span class="p">{</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">789</span><span class="p">,</span><span class="w"> </span><span class="py">name</span><span class="p">:</span><span class="w"> </span><span class="err">&#39;</span><span class="nc">Debug</span><span class="w"> </span><span class="py">User</span><span class="err">&#39;</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">View</span><span class="w"> </span><span class="py">trigger</span><span class="w"> </span><span class="py">log</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">trigger_name</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">execution_time_ms</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="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">error_message</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">FROM</span><span class="w"> </span><span class="py">SYSTEM</span><span class="err">.</span><span class="py">trigger_execution_log</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">WHERE</span><span class="w"> </span><span class="py">timestamp</span><span class="w"> </span><span class="err">&gt;</span><span class="w"> </span><span class="py">datetime</span><span class="p">()</span><span class="err">.</span><span class="py">minusMinutes</span><span class="p">(</span><span class="py">5</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">ORDER</span><span class="w"> </span><span class="py">BY</span><span class="w"> </span><span class="py">timestamp</span><span class="w"> </span><span class="py">DESC</span><span class="err">;</span><span class="w"> </span></span></span></code></pre></div> <h4 id="trigger-profiling" class="position-relative d-flex align-items-center group"> <span>Trigger Profiling</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="trigger-profiling" aria-haspopup="dialog" aria-label="Share link: Trigger Profiling"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Identify slow triggers:</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">Profile</span><span class="w"> </span><span class="py">trigger</span><span class="w"> </span><span class="py">execution</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">PROFILE</span><span class="w"> </span><span class="py">TRIGGER</span><span class="w"> </span><span class="py">audit_new_users</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">Returns</span><span class="p">:</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="err">--</span><span class="w"> </span><span class="nc">Trigger</span><span class="p">:</span><span class="w"> </span><span class="nc">audit_new_users</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">Execution</span><span class="w"> </span><span class="py">time</span><span class="p">:</span><span class="w"> </span><span class="nc">2</span><span class="mf">.5</span><span class="py">ms</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">Breakdown</span><span class="p">:</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="err">--</span><span class="w"> </span><span class="nc">Pattern</span><span class="w"> </span><span class="py">matching</span><span class="p">:</span><span class="w"> </span><span class="nc">0</span><span class="mf">.3</span><span class="py">ms</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">Property</span><span class="w"> </span><span class="py">access</span><span class="p">:</span><span class="w"> </span><span class="nc">0</span><span class="mf">.1</span><span class="py">ms</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">Insert</span><span class="w"> </span><span class="py">operation</span><span class="p">:</span><span class="w"> </span><span class="nc">2</span><span class="mf">.1</span><span class="py">ms</span><span class="w"> </span></span></span></code></pre></div> <h3 id="migration-strategies" class="position-relative d-flex align-items-center group"> <span>Migration Strategies</span> <button type="button" class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1" data-share-target="migration-strategies" aria-haspopup="dialog" aria-label="Share link: Migration Strategies"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h3> <h4 id="adding-hooks-to-existing-data" class="position-relative d-flex align-items-center group"> <span>Adding Hooks to Existing Data</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="adding-hooks-to-existing-data" aria-haspopup="dialog" aria-label="Share link: Adding Hooks to Existing Data"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Apply triggers to historical data:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gql" data-lang="gql"><span class="line"><span class="cl"><span class="err">--</span><span class="w"> </span><span class="py">Create</span><span class="w"> </span><span class="py">trigger</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">TRIGGER</span><span class="w"> </span><span class="py">compute_full_name</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">BEFORE</span><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="py">OR</span><span class="w"> </span><span class="py">UPDATE</span><span class="w"> </span><span class="py">ON</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">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">SET</span><span class="w"> </span><span class="py">NEW</span><span class="err">.</span><span class="py">full_name</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">NEW</span><span class="err">.</span><span class="py">first_name</span><span class="w"> </span><span class="p">||</span><span class="w"> </span><span class="err">&#39;</span><span class="w"> </span><span class="err">&#39;</span><span class="w"> </span><span class="p">||</span><span class="w"> </span><span class="py">NEW</span><span class="err">.</span><span class="py">last_name</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">Backfill</span><span class="w"> </span><span class="py">existing</span><span class="w"> </span><span class="py">data</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">MATCH</span><span class="w"> </span><span class="p">(</span><span class="py">p</span><span class="p">:</span><span class="nc">Person</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">WHERE</span><span class="w"> </span><span class="py">p</span><span class="err">.</span><span class="py">full_name</span><span class="w"> </span><span class="py">IS</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">WITH</span><span class="w"> </span><span class="py">p</span><span class="w"> </span><span class="py">LIMIT</span><span class="w"> </span><span class="py">1000</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">SET</span><span class="w"> </span><span class="py">p</span><span class="err">.</span><span class="py">full_name</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="py">p</span><span class="err">.</span><span class="py">first_name</span><span class="w"> </span><span class="p">||</span><span class="w"> </span><span class="err">&#39;</span><span class="w"> </span><span class="err">&#39;</span><span class="w"> </span><span class="p">||</span><span class="w"> </span><span class="py">p</span><span class="err">.</span><span class="py">last_name</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">Repeat</span><span class="w"> </span><span class="py">until</span><span class="w"> </span><span class="py">all</span><span class="w"> </span><span class="py">records</span><span class="w"> </span><span class="py">updated</span><span class="w"> </span></span></span></code></pre></div> <h4 id="versioning-hooks" class="position-relative d-flex align-items-center group"> <span>Versioning Hooks</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="versioning-hooks" aria-haspopup="dialog" aria-label="Share link: Versioning Hooks"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h4><p>Manage hook changes over time:</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">Drop</span><span class="w"> </span><span class="py">old</span><span class="w"> </span><span class="py">trigger</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">DROP</span><span class="w"> </span><span class="py">TRIGGER</span><span class="w"> </span><span class="py">IF</span><span class="w"> </span><span class="py">EXISTS</span><span class="w"> </span><span class="py">audit_new_users_v1</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">Create</span><span class="w"> </span><span class="py">new</span><span class="w"> </span><span class="py">version</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">TRIGGER</span><span class="w"> </span><span class="py">audit_new_users_v2</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">AFTER</span><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="py">ON</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">FOR</span><span class="w"> </span><span class="py">EACH</span><span class="w"> </span><span class="py">ROW</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="py">EXECUTE</span><span class="w"> </span><span class="py">GQL</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">INSERT</span><span class="w"> </span><span class="p">(</span><span class="py">a</span><span class="p">:</span><span class="nc">AuditLog</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">version</span><span class="p">:</span><span class="w"> </span><span class="nc">2</span><span class="p">,</span><span class="w"> </span><span class="err">--</span><span class="w"> </span><span class="py">Track</span><span class="w"> </span><span class="py">trigger</span><span class="w"> </span><span class="py">version</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">action</span><span class="p">:</span><span class="w"> </span><span class="err">&#39;</span><span class="nc">user_created</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">user_id</span><span class="p">:</span><span class="w"> </span><span class="nc">NEW</span><span class="err">.</span><span class="py">id</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">timestamp</span><span class="p">:</span><span class="w"> </span><span class="nc">NOW</span><span class="p">(),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">details</span><span class="p">:</span><span class="w"> </span><span class="nc">NEW</span><span class="err">.</span><span class="py">properties</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">ip_address</span><span class="p">:</span><span class="w"> </span><span class="nc">CURRENT_IP</span><span class="p">(),</span><span class="w"> </span><span class="err">--</span><span class="w"> </span><span class="py">New</span><span class="w"> </span><span class="py">field</span><span class="w"> </span><span class="py">in</span><span class="w"> </span><span class="py">v2</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">user_agent</span><span class="p">:</span><span class="w"> </span><span class="nc">CURRENT_USER_AGENT</span><span class="p">()</span><span class="w"> </span><span class="err">--</span><span class="w"> </span><span class="py">New</span><span class="w"> </span><span class="py">field</span><span class="w"> </span><span class="py">in</span><span class="w"> </span><span class="py">v2</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="learn-more" class="position-relative d-flex align-items-center group"> <span>Learn More</span> <button type="button" class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1" data-share-target="learn-more" aria-haspopup="dialog" aria-label="Share link: Learn More"> <i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i> <span class="visually-hidden">Share link</span> </button> </h3><ul> <li><a href="https://www.postgresql.org/docs/current/triggers.html" aria-label="Database Triggers (PostgreSQL) – opens in new window" target="_blank" rel="noopener noreferrer" >Database Triggers (PostgreSQL) <span aria-hidden="true" class="external-icon">↗</span> </a> </li> <li><a href="https://use-the-index-luke.com/sql/dml/insert" aria-label="Trigger Design Patterns – opens in new window" target="_blank" rel="noopener noreferrer" >Trigger Design Patterns <span aria-hidden="true" class="external-icon">↗</span> </a> </li> <li><a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/lnpls/plsql-triggers.html" aria-label="Oracle Triggers Documentation – opens in new window" target="_blank" rel="noopener noreferrer" >Oracle Triggers Documentation <span aria-hidden="true" class="external-icon">↗</span> </a> </li> <li><a href="https://martinfowler.com/articles/201701-event-driven.html" aria-label="Event-Driven Architecture – opens in new window" target="_blank" rel="noopener noreferrer" >Event-Driven Architecture <span aria-hidden="true" class="external-icon">↗</span> </a> </li> <li><a href="https://www.postgresql.org/docs/current/plpgsql-trigger.html" aria-label="Database Automation Best Practices – opens in new window" target="_blank" rel="noopener noreferrer" >Database Automation Best Practices <span aria-hidden="true" class="external-icon">↗</span> </a> </li> </ul>

Related Articles

No articles found with this tag yet.

Back to Home