[{"data":1,"prerenderedAt":948},["ShallowReactive",2],{"navigation":3,"\u002Fguides\u002Flifecycle-hooks":103,"\u002Fguides\u002Flifecycle-hooks-surround":943},[4,9,31,87,98],{"title":5,"path":6,"stem":7,"icon":8},"Getting started","\u002Fgetting-started","01.getting-started","i-tabler-rocket",{"title":10,"icon":11,"path":12,"stem":13,"children":14,"page":30},"Concepts","i-tabler-code","\u002Fconcepts","02.concepts",[15,20,25],{"title":16,"path":17,"stem":18,"icon":19},"Architecture","\u002Fconcepts\u002Farchitecture","02.concepts\u002Farchitecture","i-tabler-sitemap",{"title":21,"path":22,"stem":23,"icon":24},"Metadata and registry","\u002Fconcepts\u002Fmetadata-and-registry","02.concepts\u002Fmetadata-and-registry","i-tabler-schema",{"title":26,"path":27,"stem":28,"icon":29},"Query Engine","\u002Fconcepts\u002Fquery-engine","02.concepts\u002Fquery-engine","i-tabler-engine",false,{"title":32,"icon":33,"path":34,"stem":35,"children":36,"page":30},"Guide","i-tabler-arrow-ramp-right","\u002Fguides","03.guides",[37,42,47,52,57,62,67,72,77,82],{"title":38,"path":39,"stem":40,"icon":41},"Audit Log","\u002Fguides\u002Faudit-log","03.guides\u002Faudit-log","i-tabler-history",{"title":43,"path":44,"stem":45,"icon":46},"Cursor pagination","\u002Fguides\u002Fcursor-pagination","03.guides\u002Fcursor-pagination","i-tabler-arrow-bar-to-down",{"title":48,"path":49,"stem":50,"icon":51},"Domain Events","\u002Fguides\u002Fdomain-events","03.guides\u002Fdomain-events","i-tabler-broadcast",{"title":53,"path":54,"stem":55,"icon":56},"Field visibility","\u002Fguides\u002Ffield-visibility","03.guides\u002Ffield-visibility","i-tabler-eye-off",{"title":58,"path":59,"stem":60,"icon":61},"Lifecycle hooks","\u002Fguides\u002Flifecycle-hooks","03.guides\u002Flifecycle-hooks","i-tabler-arrows-split",{"title":63,"path":64,"stem":65,"icon":66},"Production playground","\u002Fguides\u002Fplayground","03.guides\u002Fplayground","i-tabler-flask",{"title":68,"path":69,"stem":70,"icon":71},"Queries and filters","\u002Fguides\u002Fqueries-and-filters","03.guides\u002Fqueries-and-filters","i-tabler-filter",{"title":73,"path":74,"stem":75,"icon":76},"Relations","\u002Fguides\u002Frelations","03.guides\u002Frelations","i-tabler-link",{"title":78,"path":79,"stem":80,"icon":81},"Schema consistency","\u002Fguides\u002Fschema-consistency","03.guides\u002Fschema-consistency","i-tabler-database-search",{"title":83,"path":84,"stem":85,"icon":86},"Validation","\u002Fguides\u002Fvalidation","03.guides\u002Fvalidation","i-tabler-checkup-list",{"title":88,"icon":89,"path":90,"stem":91,"children":92,"page":30},"Adapters","i-tabler-plug","\u002Fadapters","04.adapters",[93],{"title":94,"path":95,"stem":96,"icon":97},"Drizzle adapter","\u002Fadapters\u002Fdrizzle","04.adapters\u002Fdrizzle","i-simple-icons-drizzle",{"title":99,"path":100,"stem":101,"icon":102},"Current limitations","\u002Fcurrent-limitations","05.current-limitations","i-tabler-circle-dashed-x",{"id":104,"title":58,"body":105,"description":936,"extension":937,"links":938,"meta":939,"navigation":940,"path":59,"seo":941,"stem":60,"__hash__":942},"docs\u002F03.guides\u002Flifecycle-hooks.md",{"type":106,"value":107,"toc":927},"minimark",[108,112,117,242,246,249,402,409,513,517,520,655,658,662,786,789,793,868,872,875,884,888,910,913,923],[109,110,111],"p",{},"Hooks are registered per logical table name and mutation phase.",[113,114,116],"h2",{"id":115},"register-hooks","Register hooks",[118,119,124],"pre",{"className":120,"code":121,"language":122,"meta":123,"style":123},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","const hooks = createHooksRegistry()\n\nhooks.onBeforeCreate('users', normalizeEmail)\nhooks.onAfterCreate('users', createProfile)\n\nconst engine = createQueryEngine(registry, adapter, hooks)\n","ts","",[125,126,127,151,158,188,211,216],"code",{"__ignoreMap":123},[128,129,132,136,140,144,148],"span",{"class":130,"line":131},"line",1,[128,133,135],{"class":134},"spNyl","const",[128,137,139],{"class":138},"sTEyZ"," hooks ",[128,141,143],{"class":142},"sMK4o","=",[128,145,147],{"class":146},"s2Zo4"," createHooksRegistry",[128,149,150],{"class":138},"()\n",[128,152,154],{"class":130,"line":153},2,[128,155,157],{"emptyLinePlaceholder":156},true,"\n",[128,159,161,164,167,170,173,176,180,182,185],{"class":130,"line":160},3,[128,162,163],{"class":138},"hooks",[128,165,166],{"class":142},".",[128,168,169],{"class":146},"onBeforeCreate",[128,171,172],{"class":138},"(",[128,174,175],{"class":142},"'",[128,177,179],{"class":178},"sfazB","users",[128,181,175],{"class":142},[128,183,184],{"class":142},",",[128,186,187],{"class":138}," normalizeEmail)\n",[128,189,191,193,195,198,200,202,204,206,208],{"class":130,"line":190},4,[128,192,163],{"class":138},[128,194,166],{"class":142},[128,196,197],{"class":146},"onAfterCreate",[128,199,172],{"class":138},[128,201,175],{"class":142},[128,203,179],{"class":178},[128,205,175],{"class":142},[128,207,184],{"class":142},[128,209,210],{"class":138}," createProfile)\n",[128,212,214],{"class":130,"line":213},5,[128,215,157],{"emptyLinePlaceholder":156},[128,217,219,221,224,226,229,232,234,237,239],{"class":130,"line":218},6,[128,220,135],{"class":134},[128,222,223],{"class":138}," engine ",[128,225,143],{"class":142},[128,227,228],{"class":146}," createQueryEngine",[128,230,231],{"class":138},"(registry",[128,233,184],{"class":142},[128,235,236],{"class":138}," adapter",[128,238,184],{"class":142},[128,240,241],{"class":138}," hooks)\n",[113,243,245],{"id":244},"before-hooks","Before hooks",[109,247,248],{},"Before-create and before-update hooks transform data. The result of one hook becomes the input of the next.",[118,250,252],{"className":120,"code":251,"language":122,"meta":123,"style":123},"hooks.onBeforeCreate('users', async (data, context) => ({\n  ...data,\n  email: String(data.email).trim().toLowerCase(),\n  createdBy: (context.user as { id?: string } | undefined)?.id\n}))\n",[125,253,254,298,308,345,394],{"__ignoreMap":123},[128,255,256,258,260,262,264,266,268,270,272,275,278,282,284,287,290,293,295],{"class":130,"line":131},[128,257,163],{"class":138},[128,259,166],{"class":142},[128,261,169],{"class":146},[128,263,172],{"class":138},[128,265,175],{"class":142},[128,267,179],{"class":178},[128,269,175],{"class":142},[128,271,184],{"class":142},[128,273,274],{"class":134}," async",[128,276,277],{"class":142}," (",[128,279,281],{"class":280},"sHdIc","data",[128,283,184],{"class":142},[128,285,286],{"class":280}," context",[128,288,289],{"class":142},")",[128,291,292],{"class":134}," =>",[128,294,277],{"class":138},[128,296,297],{"class":142},"{\n",[128,299,300,303,305],{"class":130,"line":153},[128,301,302],{"class":142},"  ...",[128,304,281],{"class":138},[128,306,307],{"class":142},",\n",[128,309,310,314,317,320,323,325,328,330,333,336,338,341,343],{"class":130,"line":160},[128,311,313],{"class":312},"swJcz","  email",[128,315,316],{"class":142},":",[128,318,319],{"class":146}," String",[128,321,322],{"class":138},"(data",[128,324,166],{"class":142},[128,326,327],{"class":138},"email)",[128,329,166],{"class":142},[128,331,332],{"class":146},"trim",[128,334,335],{"class":138},"()",[128,337,166],{"class":142},[128,339,340],{"class":146},"toLowerCase",[128,342,335],{"class":138},[128,344,307],{"class":142},[128,346,347,350,352,355,357,360,364,367,370,373,377,380,383,386,388,391],{"class":130,"line":190},[128,348,349],{"class":312},"  createdBy",[128,351,316],{"class":142},[128,353,354],{"class":138}," (context",[128,356,166],{"class":142},[128,358,359],{"class":138},"user ",[128,361,363],{"class":362},"s7zQu","as",[128,365,366],{"class":142}," {",[128,368,369],{"class":312}," id",[128,371,372],{"class":142},"?:",[128,374,376],{"class":375},"sBMFI"," string",[128,378,379],{"class":142}," }",[128,381,382],{"class":142}," |",[128,384,385],{"class":375}," undefined",[128,387,289],{"class":138},[128,389,390],{"class":142},"?.",[128,392,393],{"class":138},"id\n",[128,395,396,399],{"class":130,"line":213},[128,397,398],{"class":142},"}",[128,400,401],{"class":138},"))\n",[109,403,404,405,408],{},"Before-delete hooks receive the effective ",[125,406,407],{},"QueryFilter"," and return no transformed value.",[118,410,412],{"className":120,"code":411,"language":122,"meta":123,"style":123},"hooks.onBeforeDelete('users', async (where, context) => {\n  if (!canDeleteUsers(context.user)) {\n    throw new Error('Deletion is not allowed.')\n  }\n})\n",[125,413,414,451,479,502,507],{"__ignoreMap":123},[128,415,416,418,420,423,425,427,429,431,433,435,437,440,442,444,446,448],{"class":130,"line":131},[128,417,163],{"class":138},[128,419,166],{"class":142},[128,421,422],{"class":146},"onBeforeDelete",[128,424,172],{"class":138},[128,426,175],{"class":142},[128,428,179],{"class":178},[128,430,175],{"class":142},[128,432,184],{"class":142},[128,434,274],{"class":134},[128,436,277],{"class":142},[128,438,439],{"class":280},"where",[128,441,184],{"class":142},[128,443,286],{"class":280},[128,445,289],{"class":142},[128,447,292],{"class":134},[128,449,450],{"class":142}," {\n",[128,452,453,456,458,461,464,466,469,471,474,477],{"class":130,"line":153},[128,454,455],{"class":362},"  if",[128,457,277],{"class":312},[128,459,460],{"class":142},"!",[128,462,463],{"class":146},"canDeleteUsers",[128,465,172],{"class":312},[128,467,468],{"class":138},"context",[128,470,166],{"class":142},[128,472,473],{"class":138},"user",[128,475,476],{"class":312},")) ",[128,478,297],{"class":142},[128,480,481,484,487,490,492,494,497,499],{"class":130,"line":160},[128,482,483],{"class":362},"    throw",[128,485,486],{"class":142}," new",[128,488,489],{"class":146}," Error",[128,491,172],{"class":312},[128,493,175],{"class":142},[128,495,496],{"class":178},"Deletion is not allowed.",[128,498,175],{"class":142},[128,500,501],{"class":312},")\n",[128,503,504],{"class":130,"line":190},[128,505,506],{"class":142},"  }\n",[128,508,509,511],{"class":130,"line":213},[128,510,398],{"class":142},[128,512,501],{"class":138},[113,514,516],{"id":515},"after-hooks","After hooks",[109,518,519],{},"After-create and after-update hooks receive the entity returned by the adapter.",[118,521,523],{"className":120,"code":522,"language":122,"meta":123,"style":123},"hooks.onAfterUpdate('users', async (entity, context) => {\n  await context.adapter.insert('auditEntries', {\n    id: crypto.randomUUID(),\n    entityId: entity.id,\n    operation: context.operation\n  })\n})\n",[125,524,525,561,591,610,627,641,648],{"__ignoreMap":123},[128,526,527,529,531,534,536,538,540,542,544,546,548,551,553,555,557,559],{"class":130,"line":131},[128,528,163],{"class":138},[128,530,166],{"class":142},[128,532,533],{"class":146},"onAfterUpdate",[128,535,172],{"class":138},[128,537,175],{"class":142},[128,539,179],{"class":178},[128,541,175],{"class":142},[128,543,184],{"class":142},[128,545,274],{"class":134},[128,547,277],{"class":142},[128,549,550],{"class":280},"entity",[128,552,184],{"class":142},[128,554,286],{"class":280},[128,556,289],{"class":142},[128,558,292],{"class":134},[128,560,450],{"class":142},[128,562,563,566,568,570,573,575,578,580,582,585,587,589],{"class":130,"line":153},[128,564,565],{"class":362},"  await",[128,567,286],{"class":138},[128,569,166],{"class":142},[128,571,572],{"class":138},"adapter",[128,574,166],{"class":142},[128,576,577],{"class":146},"insert",[128,579,172],{"class":312},[128,581,175],{"class":142},[128,583,584],{"class":178},"auditEntries",[128,586,175],{"class":142},[128,588,184],{"class":142},[128,590,450],{"class":142},[128,592,593,596,598,601,603,606,608],{"class":130,"line":160},[128,594,595],{"class":312},"    id",[128,597,316],{"class":142},[128,599,600],{"class":138}," crypto",[128,602,166],{"class":142},[128,604,605],{"class":146},"randomUUID",[128,607,335],{"class":312},[128,609,307],{"class":142},[128,611,612,615,617,620,622,625],{"class":130,"line":190},[128,613,614],{"class":312},"    entityId",[128,616,316],{"class":142},[128,618,619],{"class":138}," entity",[128,621,166],{"class":142},[128,623,624],{"class":138},"id",[128,626,307],{"class":142},[128,628,629,632,634,636,638],{"class":130,"line":213},[128,630,631],{"class":312},"    operation",[128,633,316],{"class":142},[128,635,286],{"class":138},[128,637,166],{"class":142},[128,639,640],{"class":138},"operation\n",[128,642,643,646],{"class":130,"line":218},[128,644,645],{"class":142},"  }",[128,647,501],{"class":312},[128,649,651,653],{"class":130,"line":650},7,[128,652,398],{"class":142},[128,654,501],{"class":138},[109,656,657],{},"After-delete hooks receive context only.",[113,659,661],{"id":660},"hook-context","Hook context",[118,663,665],{"className":120,"code":664,"language":122,"meta":123,"style":123},"interface HookContext {\n  table: string\n  operation: 'create' | 'update' | 'delete'\n  metadata: TableMetadata\n  adapter: DatabaseAdapter\n  requestId?: string\n  tenantId?: string\n  user?: unknown\n  [key: string]: unknown\n}\n",[125,666,667,677,687,721,731,741,750,759,770,780],{"__ignoreMap":123},[128,668,669,672,675],{"class":130,"line":131},[128,670,671],{"class":134},"interface",[128,673,674],{"class":375}," HookContext",[128,676,450],{"class":142},[128,678,679,682,684],{"class":130,"line":153},[128,680,681],{"class":312},"  table",[128,683,316],{"class":142},[128,685,686],{"class":375}," string\n",[128,688,689,692,694,697,700,702,704,706,709,711,713,715,718],{"class":130,"line":160},[128,690,691],{"class":312},"  operation",[128,693,316],{"class":142},[128,695,696],{"class":142}," '",[128,698,699],{"class":178},"create",[128,701,175],{"class":142},[128,703,382],{"class":142},[128,705,696],{"class":142},[128,707,708],{"class":178},"update",[128,710,175],{"class":142},[128,712,382],{"class":142},[128,714,696],{"class":142},[128,716,717],{"class":178},"delete",[128,719,720],{"class":142},"'\n",[128,722,723,726,728],{"class":130,"line":190},[128,724,725],{"class":312},"  metadata",[128,727,316],{"class":142},[128,729,730],{"class":375}," TableMetadata\n",[128,732,733,736,738],{"class":130,"line":213},[128,734,735],{"class":312},"  adapter",[128,737,316],{"class":142},[128,739,740],{"class":375}," DatabaseAdapter\n",[128,742,743,746,748],{"class":130,"line":218},[128,744,745],{"class":312},"  requestId",[128,747,372],{"class":142},[128,749,686],{"class":375},[128,751,752,755,757],{"class":130,"line":650},[128,753,754],{"class":312},"  tenantId",[128,756,372],{"class":142},[128,758,686],{"class":375},[128,760,762,765,767],{"class":130,"line":761},8,[128,763,764],{"class":312},"  user",[128,766,372],{"class":142},[128,768,769],{"class":375}," unknown\n",[128,771,773,776,778],{"class":130,"line":772},9,[128,774,775],{"class":138},"  [key: string]",[128,777,316],{"class":142},[128,779,769],{"class":375},[128,781,783],{"class":130,"line":782},10,[128,784,785],{"class":142},"}\n",[109,787,788],{},"The adapter is bound to the active transaction, so related database work performed by a hook remains atomic.",[113,790,792],{"id":791},"per-operation-behavior","Per-operation behavior",[794,795,796,812],"table",{},[797,798,799],"thead",{},[800,801,802,806,809],"tr",{},[803,804,805],"th",{},"Operation",[803,807,808],{},"Before input",[803,810,811],{},"After input",[813,814,815,826,837,848,858],"tbody",{},[800,816,817,820,823],{},[818,819,699],"td",{},[818,821,822],{},"resolved creation data",[818,824,825],{},"inserted entity",[800,827,828,831,834],{},[818,829,830],{},"updateOne",[818,832,833],{},"patch",[818,835,836],{},"updated entity",[800,838,839,842,845],{},[818,840,841],{},"updateMany",[818,843,844],{},"one shared patch",[818,846,847],{},"hook runs for each updated entity",[800,849,850,853,856],{},[818,851,852],{},"deleteOne",[818,854,855],{},"primary-key filter of loaded entity",[818,857,468],{},[800,859,860,863,866],{},[818,861,862],{},"deleteMany",[818,864,865],{},"original filter",[818,867,468],{},[113,869,871],{"id":870},"failure-semantics","Failure semantics",[109,873,874],{},"Hooks run sequentially. If a before or after hook throws, the adapter transaction callback rejects and Drizzle rolls the transaction back.",[876,877,881],"callout",{"color":878,"icon":879,"variant":880},"warning","i-tabler-clock-exclamation","subtle",[109,882,883],{},"Do not perform slow, non-transactional external calls directly inside hooks.\nEmit a Domain Event from an application transaction and let the built-in outbox\nprocessor deliver emails, webhooks or messages asynchronously.",[113,885,887],{"id":886},"good-uses","Good uses",[889,890,891,895,898,901,904,907],"ul",{},[892,893,894],"li",{},"normalization and derived fields;",[892,896,897],{},"authorization checks that require mutation context;",[892,899,900],{},"tenant field injection;",[892,902,903],{},"maintaining domain records that belong to the same transaction;",[892,905,906],{},"maintaining related records atomically;",[892,908,909],{},"rejecting invalid domain transitions.",[109,911,912],{},"Hooks complement validators. Use validators for data validity and hooks for mutation behavior.",[109,914,915,916,919,920,922],{},"Use the dedicated ",[917,918,38],"a",{"href":39}," and\n",[917,921,48],{"href":49}," APIs instead of hand-written\naudit or outbox hooks.",[924,925,926],"style",{},"html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}",{"title":123,"searchDepth":131,"depth":153,"links":928},[929,930,931,932,933,934,935],{"id":115,"depth":153,"text":116},{"id":244,"depth":153,"text":245},{"id":515,"depth":153,"text":516},{"id":660,"depth":153,"text":661},{"id":791,"depth":153,"text":792},{"id":870,"depth":153,"text":871},{"id":886,"depth":153,"text":887},"Run ordered domain behavior around transactional mutations.","md",null,{},{"icon":61},{"title":58,"description":936},"GXVZQoHJafQIR2t-gSxkGkwZmJQuOqUQPztYEAjiCfI",[944,946],{"title":53,"path":54,"stem":55,"description":945,"icon":56,"children":-1},"Remove hidden and context-sensitive fields from every engine result.",{"title":63,"path":64,"stem":65,"description":947,"icon":66,"children":-1},"Exercise the built package against an isolated PostgreSQL database.",1783784235545]