[{"data":1,"prerenderedAt":1401},["ShallowReactive",2],{"docs-nav:en":3,"docs:\u002Fdocs\u002Fschema\u002Fentities":134},[4],{"title":5,"path":6,"stem":7,"children":8},"Docs","\u002Fdocs","docs",[9,12,16,20,24,42,63,92,113],{"title":10,"path":6,"stem":11},"What is Fougere","docs\u002Findex",{"title":13,"path":14,"stem":15},"Getting started","\u002Fdocs\u002Fgetting-started","docs\u002F01.getting-started",{"title":17,"path":18,"stem":19},"Existing Nuxt app","\u002Fdocs\u002Fexisting-app","docs\u002F02.existing-app",{"title":21,"path":22,"stem":23},"The CLI","\u002Fdocs\u002Fcli","docs\u002F03.cli",{"title":25,"path":26,"stem":27,"children":28,"page":41},"Concepts","\u002Fdocs\u002Fconcepts","docs\u002F2.concepts",[29,33,37],{"title":30,"path":31,"stem":32},"Philosophy","\u002Fdocs\u002Fconcepts\u002Fphilosophy","docs\u002F2.concepts\u002F1.philosophy",{"title":34,"path":35,"stem":36},"The Frond","\u002Fdocs\u002Fconcepts\u002Ffrond","docs\u002F2.concepts\u002F2.frond",{"title":38,"path":39,"stem":40},"The shortest path","\u002Fdocs\u002Fconcepts\u002Fshortest-path","docs\u002F2.concepts\u002F3.shortest-path",false,{"title":43,"path":44,"stem":45,"children":46,"page":41},"Schema","\u002Fdocs\u002Fschema","docs\u002F3.schema",[47,51,55,59],{"title":48,"path":49,"stem":50},"Entities","\u002Fdocs\u002Fschema\u002Fentities","docs\u002F3.schema\u002F1.entities",{"title":52,"path":53,"stem":54},"Views","\u002Fdocs\u002Fschema\u002Fviews","docs\u002F3.schema\u002F2.views",{"title":56,"path":57,"stem":58},"The identity card","\u002Fdocs\u002Fschema\u002Fcard","docs\u002F3.schema\u002F3.card",{"title":60,"path":61,"stem":62},"Standard Schema","\u002Fdocs\u002Fschema\u002Fstandard-schema","docs\u002F3.schema\u002F4.standard-schema",{"title":64,"path":65,"stem":66,"children":67,"page":41},"Business","\u002Fdocs\u002Fbusiness","docs\u002F4.business",[68,72,76,80,84,88],{"title":69,"path":70,"stem":71},"Handlers","\u002Fdocs\u002Fbusiness\u002Fhandlers","docs\u002F4.business\u002F1.handlers",{"title":73,"path":74,"stem":75},"Presenters","\u002Fdocs\u002Fbusiness\u002Fpresenters","docs\u002F4.business\u002F2.presenters",{"title":77,"path":78,"stem":79},"Collectors","\u002Fdocs\u002Fbusiness\u002Fcollectors","docs\u002F4.business\u002F3.collectors",{"title":81,"path":82,"stem":83},"Errors","\u002Fdocs\u002Fbusiness\u002Ferrors","docs\u002F4.business\u002F4.errors",{"title":85,"path":86,"stem":87},"Seeds","\u002Fdocs\u002Fbusiness\u002Fseeds","docs\u002F4.business\u002F5.seeds",{"title":89,"path":90,"stem":91},"Facts","\u002Fdocs\u002Fbusiness\u002Ffacts","docs\u002F4.business\u002F6.facts",{"title":93,"path":94,"stem":95,"children":96,"page":41},"Client","\u002Fdocs\u002Fclient","docs\u002F5.client",[97,101,105,109],{"title":98,"path":99,"stem":100},"Queries & commands","\u002Fdocs\u002Fclient\u002Fqueries-commands","docs\u002F5.client\u002F1.queries-commands",{"title":102,"path":103,"stem":104},"Forms","\u002Fdocs\u002Fclient\u002Fforms","docs\u002F5.client\u002F2.forms",{"title":106,"path":107,"stem":108},"Session","\u002Fdocs\u002Fclient\u002Fsession","docs\u002F5.client\u002F3.session",{"title":110,"path":111,"stem":112},"invoke","\u002Fdocs\u002Fclient\u002Finvoke","docs\u002F5.client\u002F4.invoke",{"title":114,"path":115,"stem":116,"children":117,"page":41},"Infrastructure","\u002Fdocs\u002Finfra","docs\u002F6.infra",[118,122,126,130],{"title":119,"path":120,"stem":121},"The gradient","\u002Fdocs\u002Finfra\u002Fgradient","docs\u002F6.infra\u002F1.gradient",{"title":123,"path":124,"stem":125},"Surfaces — REST & GraphQL","\u002Fdocs\u002Finfra\u002Fsurfaces","docs\u002F6.infra\u002F2.surfaces",{"title":127,"path":128,"stem":129},"Deployment","\u002Fdocs\u002Finfra\u002Fdeployment","docs\u002F6.infra\u002F3.deployment",{"title":131,"path":132,"stem":133},"Hosts","\u002Fdocs\u002Finfra\u002Fhosts","docs\u002F6.infra\u002F4.hosts",{"id":135,"title":48,"body":136,"description":1396,"extension":1397,"meta":1398,"navigation":264,"path":49,"seo":1399,"stem":50,"__hash__":1400},"docs_en\u002Fdocs\u002F3.schema\u002F1.entities.md",{"type":137,"value":138,"toc":1389},"minimark",[139,143,152,529,543,548,551,722,725,807,828,835,942,949,952,991,994,1081,1088,1100,1105,1115,1122,1178,1181,1188,1192,1195,1298,1320,1334,1338,1345,1373,1379,1385],[140,141,48],"h1",{"id":142},"entities",[144,145,146,147,151],"p",{},"An entity is a class extending the ",[148,149,150],"code",{},"entity()"," factory. It provides the TypeScript type,\nvalidation, and the metadata read by adapters.",[153,154,159],"pre",{"className":155,"code":156,"language":157,"meta":158,"style":158},"language-ts shiki shiki-themes material-theme-lighter github-light github-dark","import { entity, primary, text, ref, created, oneOf, date, readOnly, optional } from '@fougere\u002Fschema';\nimport Author from '.\u002FAuthor.js';\n\nexport default class Post extends entity({\n  id: primary(),\n  slug: text({ min: 1, max: 80 }),\n  title: text({ min: 1, max: 160 }),\n  body: optional(text()),\n  authorId: ref(Author),\n  createdAt: created(),\n  status: readOnly(oneOf('draft', 'published', { default: 'draft' })),\n  publishedAt: readOnly(optional(date())),\n}) {}\n","ts","",[148,160,161,239,259,266,295,313,354,389,409,424,438,492,517],{"__ignoreMap":158},[162,163,166,170,174,178,181,184,186,189,191,194,196,199,201,204,206,209,211,214,216,219,222,225,229,233,236],"span",{"class":164,"line":165},"line",1,[162,167,169],{"class":168},"sVHd0","import",[162,171,173],{"class":172},"sP7_E"," {",[162,175,177],{"class":176},"su5hD"," entity",[162,179,180],{"class":172},",",[162,182,183],{"class":176}," primary",[162,185,180],{"class":172},[162,187,188],{"class":176}," text",[162,190,180],{"class":172},[162,192,193],{"class":176}," ref",[162,195,180],{"class":172},[162,197,198],{"class":176}," created",[162,200,180],{"class":172},[162,202,203],{"class":176}," oneOf",[162,205,180],{"class":172},[162,207,208],{"class":176}," date",[162,210,180],{"class":172},[162,212,213],{"class":176}," readOnly",[162,215,180],{"class":172},[162,217,218],{"class":176}," optional",[162,220,221],{"class":172}," }",[162,223,224],{"class":168}," from",[162,226,228],{"class":227},"sjJ54"," '",[162,230,232],{"class":231},"s_sjI","@fougere\u002Fschema",[162,234,235],{"class":227},"'",[162,237,238],{"class":172},";\n",[162,240,242,244,247,250,252,255,257],{"class":164,"line":241},2,[162,243,169],{"class":168},[162,245,246],{"class":176}," Author ",[162,248,249],{"class":168},"from",[162,251,228],{"class":227},[162,253,254],{"class":231},".\u002FAuthor.js",[162,256,235],{"class":227},[162,258,238],{"class":172},[162,260,262],{"class":164,"line":261},3,[162,263,265],{"emptyLinePlaceholder":264},true,"\n",[162,267,269,272,275,279,283,286,289,292],{"class":164,"line":268},4,[162,270,271],{"class":168},"export",[162,273,274],{"class":168}," default",[162,276,278],{"class":277},"sbsja"," class",[162,280,282],{"class":281},"sbgvK"," Post",[162,284,285],{"class":277}," extends",[162,287,177],{"class":288},"sGLFI",[162,290,291],{"class":176},"(",[162,293,294],{"class":172},"{\n",[162,296,298,302,305,307,310],{"class":164,"line":297},5,[162,299,301],{"class":300},"skxfh","  id",[162,303,304],{"class":172},":",[162,306,183],{"class":288},[162,308,309],{"class":176},"()",[162,311,312],{"class":172},",\n",[162,314,316,319,321,323,325,328,331,333,337,339,342,344,347,349,352],{"class":164,"line":315},6,[162,317,318],{"class":300},"  slug",[162,320,304],{"class":172},[162,322,188],{"class":288},[162,324,291],{"class":176},[162,326,327],{"class":172},"{",[162,329,330],{"class":300}," min",[162,332,304],{"class":172},[162,334,336],{"class":335},"srdBf"," 1",[162,338,180],{"class":172},[162,340,341],{"class":300}," max",[162,343,304],{"class":172},[162,345,346],{"class":335}," 80",[162,348,221],{"class":172},[162,350,351],{"class":176},")",[162,353,312],{"class":172},[162,355,357,360,362,364,366,368,370,372,374,376,378,380,383,385,387],{"class":164,"line":356},7,[162,358,359],{"class":300},"  title",[162,361,304],{"class":172},[162,363,188],{"class":288},[162,365,291],{"class":176},[162,367,327],{"class":172},[162,369,330],{"class":300},[162,371,304],{"class":172},[162,373,336],{"class":335},[162,375,180],{"class":172},[162,377,341],{"class":300},[162,379,304],{"class":172},[162,381,382],{"class":335}," 160",[162,384,221],{"class":172},[162,386,351],{"class":176},[162,388,312],{"class":172},[162,390,392,395,397,399,401,404,407],{"class":164,"line":391},8,[162,393,394],{"class":300},"  body",[162,396,304],{"class":172},[162,398,218],{"class":288},[162,400,291],{"class":176},[162,402,403],{"class":288},"text",[162,405,406],{"class":176},"())",[162,408,312],{"class":172},[162,410,412,415,417,419,422],{"class":164,"line":411},9,[162,413,414],{"class":300},"  authorId",[162,416,304],{"class":172},[162,418,193],{"class":288},[162,420,421],{"class":176},"(Author)",[162,423,312],{"class":172},[162,425,427,430,432,434,436],{"class":164,"line":426},10,[162,428,429],{"class":300},"  createdAt",[162,431,304],{"class":172},[162,433,198],{"class":288},[162,435,309],{"class":176},[162,437,312],{"class":172},[162,439,441,444,446,448,450,453,455,457,460,462,464,466,469,471,473,475,477,479,481,483,485,487,490],{"class":164,"line":440},11,[162,442,443],{"class":300},"  status",[162,445,304],{"class":172},[162,447,213],{"class":288},[162,449,291],{"class":176},[162,451,452],{"class":288},"oneOf",[162,454,291],{"class":176},[162,456,235],{"class":227},[162,458,459],{"class":231},"draft",[162,461,235],{"class":227},[162,463,180],{"class":172},[162,465,228],{"class":227},[162,467,468],{"class":231},"published",[162,470,235],{"class":227},[162,472,180],{"class":172},[162,474,173],{"class":172},[162,476,274],{"class":300},[162,478,304],{"class":172},[162,480,228],{"class":227},[162,482,459],{"class":231},[162,484,235],{"class":227},[162,486,221],{"class":172},[162,488,489],{"class":176},"))",[162,491,312],{"class":172},[162,493,495,498,500,502,504,507,509,512,515],{"class":164,"line":494},12,[162,496,497],{"class":300},"  publishedAt",[162,499,304],{"class":172},[162,501,213],{"class":288},[162,503,291],{"class":176},[162,505,506],{"class":288},"optional",[162,508,291],{"class":176},[162,510,511],{"class":288},"date",[162,513,514],{"class":176},"()))",[162,516,312],{"class":172},[162,518,520,523,526],{"class":164,"line":519},13,[162,521,522],{"class":172},"}",[162,524,525],{"class":176},") ",[162,527,528],{"class":172},"{}\n",[144,530,531,532,535,536,539,540,542],{},"The class name is used as the identity: ",[148,533,534],{},"Post.name"," names the SQLite table, the GraphQL\ntype, the registration key (",[148,537,538],{},"post","), and the DI match. ",[148,541,150],{}," takes no separate name.",[544,545,547],"h2",{"id":546},"field-vocabulary","Field vocabulary",[144,549,550],{},"Value fields:",[552,553,554,570],"table",{},[555,556,557],"thead",{},[558,559,560,564,567],"tr",{},[561,562,563],"th",{},"Helper",[561,565,566],{},"Type",[561,568,569],{},"Options",[571,572,573,604,622,639,662,678,693,707],"tbody",{},[558,574,575,581,586],{},[576,577,578],"td",{},[148,579,580],{},"text(opts?)",[576,582,583],{},[148,584,585],{},"string",[576,587,588,591,592,591,595,591,598,591,601],{},[148,589,590],{},"min",", ",[148,593,594],{},"max",[148,596,597],{},"pattern",[148,599,600],{},"format",[148,602,603],{},"default",[558,605,606,611,615],{},[576,607,608],{},[148,609,610],{},"email(opts?)",[576,612,613],{},[148,614,585],{},[576,616,617,619,620],{},[148,618,403],{}," options minus ",[148,621,600],{},[558,623,624,629,633],{},[576,625,626],{},[148,627,628],{},"url(opts?)",[576,630,631],{},[148,632,585],{},[576,634,635,619,637],{},[148,636,403],{},[148,638,600],{},[558,640,641,646,651],{},[576,642,643],{},[148,644,645],{},"number(opts?)",[576,647,648],{},[148,649,650],{},"number",[576,652,653,591,655,591,657,591,660],{},[148,654,590],{},[148,656,594],{},[148,658,659],{},"integer",[148,661,603],{},[558,663,664,669,674],{},[576,665,666],{},[148,667,668],{},"bool(opts?)",[576,670,671],{},[148,672,673],{},"boolean",[576,675,676],{},[148,677,603],{},[558,679,680,685,690],{},[576,681,682],{},[148,683,684],{},"date()",[576,686,687],{},[148,688,689],{},"Date",[576,691,692],{},"—",[558,694,695,700,703],{},[576,696,697],{},[148,698,699],{},"oneOf(...values, opts?)",[576,701,702],{},"union of literals",[576,704,705],{},[148,706,603],{},[558,708,709,714,719],{},[576,710,711],{},[148,712,713],{},"list(item, opts?)",[576,715,716],{},[148,717,718],{},"T[]",[576,720,721],{},"item is any field",[144,723,724],{},"Role fields:",[552,726,727,736],{},[555,728,729],{},[558,730,731,733],{},[561,732,563],{},[561,734,735],{},"Meaning",[571,737,738,751,768,778,793],{},[558,739,740,745],{},[576,741,742],{},[148,743,744],{},"primary()",[576,746,747,748],{},"primary key, generated — also wraps a field: ",[148,749,750],{},"primary(text())",[558,752,753,758],{},[576,754,755],{},[148,756,757],{},"ref(Entity)",[576,759,760,761,763,764,767],{},"foreign key (",[148,762,585],{},"); accepts ",[148,765,766],{},"() => Entity"," for cycles",[558,769,770,775],{},[576,771,772],{},[148,773,774],{},"many(Entity)",[576,776,777],{},"one-to-many — role only, no column",[558,779,780,785],{},[576,781,782],{},[148,783,784],{},"unique(f)",[576,786,787,788,792],{},"no two rows carry the same value — a constraint the ",[789,790,791],"strong",{},"database"," enforces",[558,794,795,800],{},[576,796,797],{},[148,798,799],{},"indexed(f)",[576,801,802,803,806],{},"reads filter on this often — emits ",[148,804,805],{},"CREATE INDEX",", changes no answer",[144,808,809,810,591,812,814,815,817,818,821,822,824,825,827],{},"The ",[148,811,452],{},[148,813,590],{},", and ",[148,816,594],{}," rules are also emitted as ",[148,819,820],{},"CHECK"," constraints. They therefore\napply to writes that bypass the façade, such as direct SQL or another process. ",[148,823,597],{},"\nand ",[148,826,600],{}," remain façade validations because regular-expression dialects differ across\ndatabases.",[144,829,830,831,834],{},"Some facts are about a pair, not a field. \"A book appears once in a list\" is true of\n",[148,832,833],{},"(listId, docId)"," and of neither alone, so it is declared on the entity:",[153,836,838],{"className":155,"code":837,"language":157,"meta":158,"style":158},"class ListBook extends entity({\n  id: primary(),\n  listId: ref(List),\n  docId: text(),\n}, {\n  unique: [['listId', 'docId']],\n}) {}\n",[148,839,840,856,868,882,895,903,934],{"__ignoreMap":158},[162,841,842,845,848,850,852,854],{"class":164,"line":165},[162,843,844],{"class":277},"class",[162,846,847],{"class":281}," ListBook",[162,849,285],{"class":277},[162,851,177],{"class":288},[162,853,291],{"class":176},[162,855,294],{"class":172},[162,857,858,860,862,864,866],{"class":164,"line":241},[162,859,301],{"class":300},[162,861,304],{"class":172},[162,863,183],{"class":288},[162,865,309],{"class":176},[162,867,312],{"class":172},[162,869,870,873,875,877,880],{"class":164,"line":261},[162,871,872],{"class":300},"  listId",[162,874,304],{"class":172},[162,876,193],{"class":288},[162,878,879],{"class":176},"(List)",[162,881,312],{"class":172},[162,883,884,887,889,891,893],{"class":164,"line":268},[162,885,886],{"class":300},"  docId",[162,888,304],{"class":172},[162,890,188],{"class":288},[162,892,309],{"class":176},[162,894,312],{"class":172},[162,896,897,900],{"class":164,"line":297},[162,898,899],{"class":172},"},",[162,901,902],{"class":172}," {\n",[162,904,905,908,910,913,915,918,920,922,924,927,929,932],{"class":164,"line":315},[162,906,907],{"class":300},"  unique",[162,909,304],{"class":172},[162,911,912],{"class":176}," [[",[162,914,235],{"class":227},[162,916,917],{"class":231},"listId",[162,919,235],{"class":227},[162,921,180],{"class":172},[162,923,228],{"class":227},[162,925,926],{"class":231},"docId",[162,928,235],{"class":227},[162,930,931],{"class":176},"]]",[162,933,312],{"class":172},[162,935,936,938,940],{"class":164,"line":356},[162,937,522],{"class":172},[162,939,525],{"class":176},[162,941,528],{"class":172},[144,943,944,945,948],{},"The database enforces this constraint so that concurrent writes are covered as well. A\nderivation that removes one group member also removes the group: keeping only ",[148,946,947],{},"(listId)","\nwould change the declared rule.",[144,950,951],{},"Lifecycle fields:",[552,953,954,962],{},[555,955,956],{},[558,957,958,960],{},[561,959,563],{},[561,961,735],{},[571,963,964,978],{},[558,965,966,971],{},[576,967,968],{},[148,969,970],{},"created()",[576,972,973,974,977],{},"stamped at create (",[148,975,976],{},"createdAt",") — never client-written",[558,979,980,985],{},[576,981,982],{},[148,983,984],{},"updated()",[576,986,987,988,351],{},"re-stamped at every update (",[148,989,990],{},"updatedAt",[144,992,993],{},"Wrappers (compose around any field):",[552,995,996,1009],{},[555,997,998],{},[558,999,1000,1003,1006],{},[561,1001,1002],{},"Wrapper",[561,1004,1005],{},"Axis",[561,1007,1008],{},"Effect",[571,1010,1011,1027,1043,1056,1069],{},[558,1012,1013,1018,1021],{},[576,1014,1015],{},[148,1016,1017],{},"optional(f)",[576,1019,1020],{},"shape",[576,1022,1023,1024],{},"may be absent; ",[148,1025,1026],{},"T | null",[558,1028,1029,1034,1036],{},[576,1030,1031],{},[148,1032,1033],{},"nullable(f)",[576,1035,1020],{},[576,1037,1038,1039,1042],{},"may be ",[148,1040,1041],{},"null",", must be present",[558,1044,1045,1050,1053],{},[576,1046,1047],{},[148,1048,1049],{},"immutable(f)",[576,1051,1052],{},"lifecycle",[576,1054,1055],{},"writable at create, forbidden on update",[558,1057,1058,1063,1066],{},[576,1059,1060],{},[148,1061,1062],{},"readOnly(f)",[576,1064,1065],{},"boundary",[576,1067,1068],{},"never crosses inward — output only",[558,1070,1071,1076,1078],{},[576,1072,1073],{},[148,1074,1075],{},"writeOnly(f)",[576,1077,1065],{},[576,1079,1080],{},"never crosses outward — input only (passwords)",[144,1082,1083,1084,1087],{},"Wrappers nest: ",[148,1085,1086],{},"readOnly(optional(date()))"," is a server-owned, possibly-absent date.",[1089,1090,1091],"blockquote",{},[144,1092,1093,1096,1097,1099],{},[148,1094,1095],{},"Post.validate()"," only sees the current input and therefore cannot check uniqueness\nagainst existing rows. The database enforces that rule and returns a driver error rather\nthan a field error. A ",[148,1098,744],{}," field is already unique.",[1101,1102,1104],"h3",{"id":1103},"two-ways-to-write-it-one-shape","Two ways to write it, one shape",[144,1106,1107,1110,1111,1114],{},[148,1108,1109],{},"unique(slug)"," declares a constraint on one field; ",[148,1112,1113],{},"unique: [['listId','docId']]"," declares\none across several fields. Both use the same internal representation: a list of field\ngroups.",[144,1116,1117,1118,1121],{},"Each field's ",[148,1119,1120],{},"role"," axis contains the constraints it belongs to:",[153,1123,1125],{"className":155,"code":1124,"language":157,"meta":158,"style":158},"slug.role.unique   \u002F\u002F [['slug']]                — the set of one\nlistId.role.unique \u002F\u002F [['listId', 'docId']]     — the pair, held by each member\ndocId.role.unique  \u002F\u002F [['listId', 'docId']]\n",[148,1126,1127,1146,1162],{"__ignoreMap":158},[162,1128,1129,1132,1135,1137,1139,1142],{"class":164,"line":165},[162,1130,1131],{"class":176},"slug",[162,1133,1134],{"class":172},".",[162,1136,1120],{"class":176},[162,1138,1134],{"class":172},[162,1140,1141],{"class":176},"unique   ",[162,1143,1145],{"class":1144},"sutJx","\u002F\u002F [['slug']]                — the set of one\n",[162,1147,1148,1150,1152,1154,1156,1159],{"class":164,"line":241},[162,1149,917],{"class":176},[162,1151,1134],{"class":172},[162,1153,1120],{"class":176},[162,1155,1134],{"class":172},[162,1157,1158],{"class":176},"unique ",[162,1160,1161],{"class":1144},"\u002F\u002F [['listId', 'docId']]     — the pair, held by each member\n",[162,1163,1164,1166,1168,1170,1172,1175],{"class":164,"line":261},[162,1165,926],{"class":176},[162,1167,1134],{"class":172},[162,1169,1120],{"class":176},[162,1171,1134],{"class":172},[162,1173,1174],{"class":176},"unique  ",[162,1176,1177],{"class":1144},"\u002F\u002F [['listId', 'docId']]\n",[144,1179,1180],{},"A field belonging to two constraints carries two entries. Each member contains the whole\ngroup, allowing a consumer in another language to rebuild a compound constraint.",[144,1182,1183,1184,1187],{},"A derivation that removes a member removes the group: ",[148,1185,1186],{},"Post.pick('listId')"," does not retain\nthe compound constraint.",[544,1189,1191],{"id":1190},"the-four-axes","The four axes",[144,1193,1194],{},"Every field carries four orthogonal axes — this is the model all adapters read:",[552,1196,1197,1209],{},[555,1198,1199],{},[558,1200,1201,1203,1206],{},[561,1202,1005],{},[561,1204,1205],{},"Question",[561,1207,1208],{},"Read by",[571,1210,1211,1228,1252,1273],{},[558,1212,1213,1217,1225],{},[576,1214,1215],{},[789,1216,1020],{},[576,1218,1219,1220,1224],{},"what values are valid? (the shape ",[1221,1222,1223],"em",{},"is"," JSON Schema)",[576,1226,1227],{},"validation, forms, SQL column, GraphQL scalar",[558,1229,1230,1234,1249],{},[576,1231,1232],{},[789,1233,1120],{},[576,1235,1236,1237,591,1240,591,1243,591,1246,351],{},"what part does it play? (",[148,1238,1239],{},"primary",[148,1241,1242],{},"ref",[148,1244,1245],{},"many",[148,1247,1248],{},"unique",[576,1250,1251],{},"DDL (PK\u002FFK, constraints), relations, the card",[558,1253,1254,1258,1270],{},[576,1255,1256],{},[789,1257,1052],{},[576,1259,1260,1261,591,1264,591,1267,351],{},"who writes it, when? (",[148,1262,1263],{},"auto",[148,1265,1266],{},"updated",[148,1268,1269],{},"immutable",[576,1271,1272],{},"ORM realization, constructor relaxation",[558,1274,1275,1279,1288],{},[576,1276,1277],{},[789,1278,1065],{},[576,1280,1281,1282,591,1285,351],{},"which way does it cross the API? (",[148,1283,1284],{},"readOnly",[148,1286,1287],{},"writeOnly",[576,1289,1290,1291,1294,1295],{},"io projections ",[148,1292,1293],{},"inputFields"," \u002F ",[148,1296,1297],{},"outputFields",[144,1299,1300,1301,1303,1304,1306,1307,1309,1310,1313,1314,1316,1317,1319],{},"The façade validates client input against the ",[148,1302,1020],{}," and ",[148,1305,1065],{}," axes: writing a\n",[148,1308,1284],{}," field such as ",[148,1311,1312],{},"status"," is rejected. The ORM then applies the ",[148,1315,1052],{}," axis,\nfor example by setting ",[148,1318,976],{}," and default values.",[1089,1321,1322],{},[144,1323,1324,1325,1328,1329,1333],{},"Validation rejects unknown keys with ",[148,1326,1327],{},"Unknown field"," instead of silently dropping them.\nAn accepted input therefore matches the contract exactly (see\n",[1330,1331,69],"a",{"href":1332},"\u002Fdocs\u002Fbusiness\u002Fhandlers#unknown-keys-are-refused",").",[544,1335,1337],{"id":1336},"entityvalidate","Entity.validate",[144,1339,1340,1341,1344],{},"The validation engine is edge-safe (",[148,1342,1343],{},"@cfworker\u002Fjson-schema","). The same function can run\nin the browser and in the handler:",[153,1346,1348],{"className":155,"code":1347,"language":157,"meta":158,"style":158},"Post.validate(input)\n\u002F\u002F → { success: true, data }                                    valid\n\u002F\u002F → { success: false, errors: [{ path: 'title', message }] }   invalid, per-field\n",[148,1349,1350,1363,1368],{"__ignoreMap":158},[162,1351,1352,1355,1357,1360],{"class":164,"line":165},[162,1353,1354],{"class":176},"Post",[162,1356,1134],{"class":172},[162,1358,1359],{"class":288},"validate",[162,1361,1362],{"class":176},"(input)\n",[162,1364,1365],{"class":164,"line":241},[162,1366,1367],{"class":1144},"\u002F\u002F → { success: true, data }                                    valid\n",[162,1369,1370],{"class":164,"line":261},[162,1371,1372],{"class":1144},"\u002F\u002F → { success: false, errors: [{ path: 'title', message }] }   invalid, per-field\n",[144,1374,1375,1378],{},[148,1376,1377],{},"new Post(data)"," builds an instance without validation. Generated and automatic fields are\noptional for the constructor but remain present on the resulting type.",[144,1380,1381,1382,1384],{},"Next: ",[1330,1383,52],{"href":53}," — deriving contracts from the schema.",[1386,1387,1388],"style",{},"html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}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 .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}",{"title":158,"searchDepth":241,"depth":241,"links":1390},[1391,1394,1395],{"id":546,"depth":241,"text":547,"children":1392},[1393],{"id":1103,"depth":261,"text":1104},{"id":1190,"depth":241,"text":1191},{"id":1336,"depth":241,"text":1337},"The field vocabulary, the four axes, and Entity.validate.","md",{},{"title":48,"description":1396},"IIcTExyT7gTd2FiwPivEvHHwwROpAWJFH7U629XUlOU",1786637819120]