[{"data":1,"prerenderedAt":1518},["ShallowReactive",2],{"docs-nav:fr":3,"docs:\u002Ffr\u002Fdocs\u002Finfra\u002Fsources":189},[4],{"title":5,"path":6,"stem":7,"children":8,"page":52},"Fr","\u002Ffr","fr",[9],{"title":10,"path":11,"stem":12,"children":13},"Qu'est-ce que Fougere","\u002Ffr\u002Fdocs","fr\u002Fdocs\u002Findex",[14,15,19,23,27,31,53,78,123,148],{"title":10,"path":11,"stem":12},{"title":16,"path":17,"stem":18},"Démarrer","\u002Ffr\u002Fdocs\u002Fgetting-started","fr\u002Fdocs\u002F01.getting-started",{"title":20,"path":21,"stem":22},"Une app que vous avez déjà","\u002Ffr\u002Fdocs\u002Fexisting-app","fr\u002Fdocs\u002F02.existing-app",{"title":24,"path":25,"stem":26},"Apportez votre schéma","\u002Ffr\u002Fdocs\u002Fbring-your-schema","fr\u002Fdocs\u002F03.bring-your-schema",{"title":28,"path":29,"stem":30},"La CLI","\u002Ffr\u002Fdocs\u002Fcli","fr\u002Fdocs\u002F04.cli",{"title":32,"path":33,"stem":34,"children":35,"page":52},"Concepts","\u002Ffr\u002Fdocs\u002Fconcepts","fr\u002Fdocs\u002F2.concepts",[36,40,44,48],{"title":37,"path":38,"stem":39},"Philosophie","\u002Ffr\u002Fdocs\u002Fconcepts\u002Fphilosophy","fr\u002Fdocs\u002F2.concepts\u002F1.philosophy",{"title":41,"path":42,"stem":43},"La Frond","\u002Ffr\u002Fdocs\u002Fconcepts\u002Ffrond","fr\u002Fdocs\u002F2.concepts\u002F2.frond",{"title":45,"path":46,"stem":47},"Le chemin le plus court","\u002Ffr\u002Fdocs\u002Fconcepts\u002Fshortest-path","fr\u002Fdocs\u002F2.concepts\u002F3.shortest-path",{"title":49,"path":50,"stem":51},"Le socle","\u002Ffr\u002Fdocs\u002Fconcepts\u002Fthe-base","fr\u002Fdocs\u002F2.concepts\u002F4.the-base",false,{"title":54,"path":55,"stem":56,"children":57,"page":52},"Schéma","\u002Ffr\u002Fdocs\u002Fschema","fr\u002Fdocs\u002F3.schema",[58,62,66,70,74],{"title":59,"path":60,"stem":61},"Entités","\u002Ffr\u002Fdocs\u002Fschema\u002Fentities","fr\u002Fdocs\u002F3.schema\u002F1.entities",{"title":63,"path":64,"stem":65},"Vues","\u002Ffr\u002Fdocs\u002Fschema\u002Fviews","fr\u002Fdocs\u002F3.schema\u002F2.views",{"title":67,"path":68,"stem":69},"La carte d'identité","\u002Ffr\u002Fdocs\u002Fschema\u002Fcard","fr\u002Fdocs\u002F3.schema\u002F3.card",{"title":71,"path":72,"stem":73},"Standard Schema","\u002Ffr\u002Fdocs\u002Fschema\u002Fstandard-schema","fr\u002Fdocs\u002F3.schema\u002F4.standard-schema",{"title":75,"path":76,"stem":77},"Comment un schéma bouge","\u002Ffr\u002Fdocs\u002Fschema\u002Fevolution","fr\u002Fdocs\u002F3.schema\u002F5.evolution",{"title":79,"path":80,"stem":81,"children":82,"page":52},"Métier","\u002Ffr\u002Fdocs\u002Fbusiness","fr\u002Fdocs\u002F4.business",[83,87,91,95,99,103,107,111,115,119],{"title":84,"path":85,"stem":86},"Handlers","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fhandlers","fr\u002Fdocs\u002F4.business\u002F1.handlers",{"title":88,"path":89,"stem":90},"Les ports","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fports","fr\u002Fdocs\u002F4.business\u002F10.ports",{"title":92,"path":93,"stem":94},"Presenters","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fpresenters","fr\u002Fdocs\u002F4.business\u002F2.presenters",{"title":96,"path":97,"stem":98},"Collectors","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fcollectors","fr\u002Fdocs\u002F4.business\u002F3.collectors",{"title":100,"path":101,"stem":102},"Erreurs","\u002Ffr\u002Fdocs\u002Fbusiness\u002Ferrors","fr\u002Fdocs\u002F4.business\u002F4.errors",{"title":104,"path":105,"stem":106},"Seeds","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fseeds","fr\u002Fdocs\u002F4.business\u002F5.seeds",{"title":108,"path":109,"stem":110},"Les faits","\u002Ffr\u002Fdocs\u002Fbusiness\u002Ffacts","fr\u002Fdocs\u002F4.business\u002F6.facts",{"title":112,"path":113,"stem":114},"Le port Storage","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fstorage","fr\u002Fdocs\u002F4.business\u002F7.storage",{"title":116,"path":117,"stem":118},"Des écritures qui tiennent ou tombent ensemble","\u002Ffr\u002Fdocs\u002Fbusiness\u002Ftogether","fr\u002Fdocs\u002F4.business\u002F8.together",{"title":120,"path":121,"stem":122},"Les repositories","\u002Ffr\u002Fdocs\u002Fbusiness\u002Frepositories","fr\u002Fdocs\u002F4.business\u002F9.repositories",{"title":124,"path":125,"stem":126,"children":127,"page":52},"Client","\u002Ffr\u002Fdocs\u002Fclient","fr\u002Fdocs\u002F5.client",[128,132,136,140,144],{"title":129,"path":130,"stem":131},"Queries & commands","\u002Ffr\u002Fdocs\u002Fclient\u002Fqueries-commands","fr\u002Fdocs\u002F5.client\u002F1.queries-commands",{"title":133,"path":134,"stem":135},"Formulaires","\u002Ffr\u002Fdocs\u002Fclient\u002Fforms","fr\u002Fdocs\u002F5.client\u002F2.forms",{"title":137,"path":138,"stem":139},"Session","\u002Ffr\u002Fdocs\u002Fclient\u002Fsession","fr\u002Fdocs\u002F5.client\u002F3.session",{"title":141,"path":142,"stem":143},"invoke","\u002Ffr\u002Fdocs\u002Fclient\u002Finvoke","fr\u002Fdocs\u002F5.client\u002F4.invoke",{"title":145,"path":146,"stem":147},"Back-office","\u002Ffr\u002Fdocs\u002Fclient\u002Fadmin","fr\u002Fdocs\u002F5.client\u002F5.admin",{"title":149,"path":150,"stem":151,"children":152,"page":52},"Infrastructure","\u002Ffr\u002Fdocs\u002Finfra","fr\u002Fdocs\u002F6.infra",[153,157,161,165,169,173,177,181,185],{"title":154,"path":155,"stem":156},"Le gradient","\u002Ffr\u002Fdocs\u002Finfra\u002Fgradient","fr\u002Fdocs\u002F6.infra\u002F1.gradient",{"title":158,"path":159,"stem":160},"Surfaces — REST & GraphQL","\u002Ffr\u002Fdocs\u002Finfra\u002Fsurfaces","fr\u002Fdocs\u002F6.infra\u002F2.surfaces",{"title":162,"path":163,"stem":164},"Déploiement","\u002Ffr\u002Fdocs\u002Finfra\u002Fdeployment","fr\u002Fdocs\u002F6.infra\u002F3.deployment",{"title":166,"path":167,"stem":168},"Hôtes","\u002Ffr\u002Fdocs\u002Finfra\u002Fhosts","fr\u002Fdocs\u002F6.infra\u002F4.hosts",{"title":170,"path":171,"stem":172},"Les sources","\u002Ffr\u002Fdocs\u002Finfra\u002Fsources","fr\u002Fdocs\u002F6.infra\u002F5.sources",{"title":174,"path":175,"stem":176},"Le cycle de vie","\u002Ffr\u002Fdocs\u002Finfra\u002Flifecycle","fr\u002Fdocs\u002F6.infra\u002F6.lifecycle",{"title":178,"path":179,"stem":180},"L'identité entre Fronds","\u002Ffr\u002Fdocs\u002Finfra\u002Fidentity","fr\u002Fdocs\u002F6.infra\u002F7.identity",{"title":182,"path":183,"stem":184},"Observabilité","\u002Ffr\u002Fdocs\u002Finfra\u002Fobservability","fr\u002Fdocs\u002F6.infra\u002F8.observability",{"title":186,"path":187,"stem":188},"Tests","\u002Ffr\u002Fdocs\u002Finfra\u002Ftesting","fr\u002Fdocs\u002F6.infra\u002F9.testing",{"id":190,"title":170,"body":191,"description":1513,"extension":1514,"meta":1515,"navigation":756,"path":171,"seo":1516,"stem":172,"__hash__":1517},"docs_fr\u002Ffr\u002Fdocs\u002F6.infra\u002F5.sources.md",{"type":192,"value":193,"toc":1504},"minimark",[194,198,211,216,231,377,394,405,409,431,584,600,603,661,671,679,682,687,702,1089,1112,1116,1134,1141,1201,1215,1357,1360,1403,1414,1418,1424,1430,1447,1456,1460,1500],[195,196,170],"h1",{"id":197},"les-sources",[199,200,201,202,206,207,210],"p",{},"Une application a d'ordinaire une base et ne déclare rien. Quand elle en a plusieurs — une\narchive héritée, le réplica d'un partenaire, un entrepôt — ",[203,204,205],"code",{},"sources:"," dit quelles entités\nvivent où, et ",[203,208,209],{},"reads:"," dit quelles Fronds peuvent interroger à travers.",[212,213,215],"h2",{"id":214},"où-vivent-les-lignes","Où vivent les lignes",[199,217,218,221,222,226,227,230],{},[203,219,220],{},"sources"," nomme les endroits qui ne sont ",[223,224,225],"strong",{},"pas"," celui par défaut. Une entité qu'il ne\nnomme pas reste dans ",[203,228,229],{},"db",", donc une application à une seule base se comporte exactement\ncomme avant :",[232,233,238],"pre",{"className":234,"code":235,"language":236,"meta":237,"style":237},"language-ts shiki shiki-themes material-theme-lighter github-light github-dark","\u002F\u002F fougere.config.ts\nexport default defineFougere({\n  db: { path: '.data\u002Fapp.db' },\n  sources: {\n    archive: { path: '\u002Fmnt\u002Flegacy\u002Fcatalog.db', entities: ['Book'] },\n  },\n});\n","ts","",[203,239,240,249,271,303,314,359,365],{"__ignoreMap":237},[241,242,245],"span",{"class":243,"line":244},"line",1,[241,246,248],{"class":247},"sutJx","\u002F\u002F fougere.config.ts\n",[241,250,252,256,259,263,267],{"class":243,"line":251},2,[241,253,255],{"class":254},"sVHd0","export",[241,257,258],{"class":254}," default",[241,260,262],{"class":261},"sGLFI"," defineFougere",[241,264,266],{"class":265},"su5hD","(",[241,268,270],{"class":269},"sP7_E","{\n",[241,272,274,278,281,284,287,289,293,297,300],{"class":243,"line":273},3,[241,275,277],{"class":276},"skxfh","  db",[241,279,280],{"class":269},":",[241,282,283],{"class":269}," {",[241,285,286],{"class":276}," path",[241,288,280],{"class":269},[241,290,292],{"class":291},"sjJ54"," '",[241,294,296],{"class":295},"s_sjI",".data\u002Fapp.db",[241,298,299],{"class":291},"'",[241,301,302],{"class":269}," },\n",[241,304,306,309,311],{"class":243,"line":305},4,[241,307,308],{"class":276},"  sources",[241,310,280],{"class":269},[241,312,313],{"class":269}," {\n",[241,315,317,320,322,324,326,328,330,333,335,338,341,343,346,348,351,353,356],{"class":243,"line":316},5,[241,318,319],{"class":276},"    archive",[241,321,280],{"class":269},[241,323,283],{"class":269},[241,325,286],{"class":276},[241,327,280],{"class":269},[241,329,292],{"class":291},[241,331,332],{"class":295},"\u002Fmnt\u002Flegacy\u002Fcatalog.db",[241,334,299],{"class":291},[241,336,337],{"class":269},",",[241,339,340],{"class":276}," entities",[241,342,280],{"class":269},[241,344,345],{"class":265}," [",[241,347,299],{"class":291},[241,349,350],{"class":295},"Book",[241,352,299],{"class":291},[241,354,355],{"class":265},"] ",[241,357,358],{"class":269},"},\n",[241,360,362],{"class":243,"line":361},6,[241,363,364],{"class":269},"  },\n",[241,366,368,371,374],{"class":243,"line":367},7,[241,369,370],{"class":269},"}",[241,372,373],{"class":265},")",[241,375,376],{"class":269},";\n",[199,378,379,381,382,385,386,388,389,393],{},[203,380,350],{}," lit et écrit désormais dans ",[203,383,384],{},"archive"," ; tout le reste reste dans ",[203,387,229],{},". Le\n",[390,391,392],"a",{"href":113},"port Storage"," qu'un handler reçoit ne change pas : le placement est un\nfait sur l'application, pas sur le code qui s'en sert. Une source peut aussi être un moteur\nque l'appelant a construit — un pool que Fougere n'a pas ouvert reste un endroit où des\nlignes peuvent vivre.",[199,395,396,397,400,401,404],{},"Une ",[390,398,399],{"href":64},"dérivation"," ne fabrique pas de table à elle, sauf si elle dit\n",[203,402,403],{},".anchor()",". C'est le mot de l'entité, jamais une clé de ce fichier : un frond reste montable\nsans que son hôte sache que l'un de ses schémas détient des lignes.",[212,406,408],{"id":407},"ce-qui-réalise-une-source","Ce qui réalise une source",[199,410,411,414,415,418,419,422,423,426,427,430],{},[203,412,413],{},"source:"," nomme l'",[223,416,417],{},"adaptateur",", et ce qui est en dessous appartient à cet adaptateur — la\nforme qu'",[203,420,421],{},"adapters:"," a déjà sur une entité. ",[203,424,425],{},"dialect"," est une propriété de SQL et y reste,\nparce que seul ",[203,428,429],{},"@fougere\u002Fadapter-sql"," sait ce qu'elle vaut.",[232,432,434],{"className":234,"code":433,"language":236,"meta":237,"style":237},"export default defineFougere({\n  db: { path: '.data\u002Fapp.db' },                             \u002F\u002F `source: 'sql'` par convention\n  sources: {\n    archive: { source: 'file', path: '.\u002Frows', entities: ['Snapshot'] },\n    cache:   { source: 'memory', entities: ['Draft'] },\n  },\n});\n",[203,435,436,448,472,480,532,572,576],{"__ignoreMap":237},[241,437,438,440,442,444,446],{"class":243,"line":244},[241,439,255],{"class":254},[241,441,258],{"class":254},[241,443,262],{"class":261},[241,445,266],{"class":265},[241,447,270],{"class":269},[241,449,450,452,454,456,458,460,462,464,466,469],{"class":243,"line":251},[241,451,277],{"class":276},[241,453,280],{"class":269},[241,455,283],{"class":269},[241,457,286],{"class":276},[241,459,280],{"class":269},[241,461,292],{"class":291},[241,463,296],{"class":295},[241,465,299],{"class":291},[241,467,468],{"class":269}," },",[241,470,471],{"class":247},"                             \u002F\u002F `source: 'sql'` par convention\n",[241,473,474,476,478],{"class":243,"line":273},[241,475,308],{"class":276},[241,477,280],{"class":269},[241,479,313],{"class":269},[241,481,482,484,486,488,491,493,495,498,500,502,504,506,508,511,513,515,517,519,521,523,526,528,530],{"class":243,"line":305},[241,483,319],{"class":276},[241,485,280],{"class":269},[241,487,283],{"class":269},[241,489,490],{"class":276}," source",[241,492,280],{"class":269},[241,494,292],{"class":291},[241,496,497],{"class":295},"file",[241,499,299],{"class":291},[241,501,337],{"class":269},[241,503,286],{"class":276},[241,505,280],{"class":269},[241,507,292],{"class":291},[241,509,510],{"class":295},".\u002Frows",[241,512,299],{"class":291},[241,514,337],{"class":269},[241,516,340],{"class":276},[241,518,280],{"class":269},[241,520,345],{"class":265},[241,522,299],{"class":291},[241,524,525],{"class":295},"Snapshot",[241,527,299],{"class":291},[241,529,355],{"class":265},[241,531,358],{"class":269},[241,533,534,537,539,542,544,546,548,551,553,555,557,559,561,563,566,568,570],{"class":243,"line":316},[241,535,536],{"class":276},"    cache",[241,538,280],{"class":269},[241,540,541],{"class":269},"   {",[241,543,490],{"class":276},[241,545,280],{"class":269},[241,547,292],{"class":291},[241,549,550],{"class":295},"memory",[241,552,299],{"class":291},[241,554,337],{"class":269},[241,556,340],{"class":276},[241,558,280],{"class":269},[241,560,345],{"class":265},[241,562,299],{"class":291},[241,564,565],{"class":295},"Draft",[241,567,299],{"class":291},[241,569,355],{"class":265},[241,571,358],{"class":269},[241,573,574],{"class":243,"line":361},[241,575,364],{"class":269},[241,577,578,580,582],{"class":243,"line":367},[241,579,370],{"class":269},[241,581,373],{"class":265},[241,583,376],{"class":269},[199,585,586,587,590,591,593,594,596,597,599],{},"Un adaptateur répond à un nom en s'enregistrant à l'import, donc rien de central ne les\nliste, et un nom auquel rien ne répond est refusé en disant ce que ce process répond. Trois\nsont livrés : ",[203,588,589],{},"sql"," (SQLite depuis un nom ; un autre moteur se construit en code et se\ntransmet), ",[203,592,497],{}," (un JSON par ligne, un répertoire par entité) et ",[203,595,550],{}," (une Map, qui est\naussi le repli d'une app sans ",[203,598,229],{},").",[199,601,602],{},"Une source énonce quatre gestes, dont seul le premier est requis :",[604,605,606,617],"table",{},[607,608,609],"thead",{},[610,611,612,615],"tr",{},[613,614],"th",{},[613,616],{},[618,619,620,631,641,651],"tbody",{},[610,621,622,628],{},[623,624,625],"td",{},[203,626,627],{},"storageFactory",[623,629,630],{},"bâtir le stockage d'une entité qui vit ici",[610,632,633,638],{},[623,634,635],{},[203,636,637],{},"migrate?",[623,639,640],{},"mettre à jour la forme de ce qu'elle tient",[610,642,643,648],{},[623,644,645],{},[203,646,647],{},"transacted?",[623,649,650],{},"exécuter une unité de travail",[610,652,653,658],{},[623,654,655],{},[203,656,657],{},"close?",[623,659,660],{},"relâcher",[199,662,663,666,667,670],{},[223,664,665],{},"L'absence répond aussi."," Une source qui ne rend aucune transaction fait qu'un\n",[390,668,669],{"href":117},"frame"," compense au lieu de transiger, et le boot dit laquelle des\ndeux il a construite :",[232,672,677],{"className":673,"code":675,"language":676},[674],"language-text","RateCard+Ledger|RateMirrorTogether — compensated: rateCard in 'archive', ledger in 'db' — no isolation\nAccount+LedgerTogether            — transaction, source 'db'\n","text",[203,678,675],{"__ignoreMap":237},[199,680,681],{},"Deux frames, une app, deux garanties — et les handlers sont les mêmes dans les deux cas.",[683,684,686],"h3",{"id":685},"en-écrire-un","En écrire un",[199,688,689,690,693,694,697,698,701],{},"Un adaptateur fournit ",[203,691,692],{},"Rows",", quatre gestes sur une collection indexée, et ",[203,695,696],{},"storageOver"," en\ndérive les treize du ",[390,699,700],{"href":113},"port de stockage",". Les pages, les critères et\nles tampons du cycle de vie ne s'écrivent pas deux fois :",[232,703,705],{"className":234,"code":704,"language":236,"meta":237,"style":237},"import { Sources, storageOver, type Rows, type Source } from '@fougere\u002Fcore';\n\nconst mapRows = (): Rows => {\n  const store = new Map();\n  return {\n    client: store,\n    get: async (key) => store.get(key),\n    has: async (key) => store.has(key),\n    set: async (key, row) => { store.set(key, row); },\n    delete: async (key) => store.delete(key),\n    all: async () => [...store.values()],\n  };\n};\n\nSources.register('memory', (): Source => ({ storageFactory: storageOver(mapRows), name: 'memory' }));\n",[203,706,707,752,758,785,807,814,826,863,896,943,976,1008,1014,1020,1025],{"__ignoreMap":237},[241,708,709,712,714,717,719,722,724,727,730,732,734,737,740,743,745,748,750],{"class":243,"line":244},[241,710,711],{"class":254},"import",[241,713,283],{"class":269},[241,715,716],{"class":265}," Sources",[241,718,337],{"class":269},[241,720,721],{"class":265}," storageOver",[241,723,337],{"class":269},[241,725,726],{"class":254}," type",[241,728,729],{"class":265}," Rows",[241,731,337],{"class":269},[241,733,726],{"class":254},[241,735,736],{"class":265}," Source",[241,738,739],{"class":269}," }",[241,741,742],{"class":254}," from",[241,744,292],{"class":291},[241,746,747],{"class":295},"@fougere\u002Fcore",[241,749,299],{"class":291},[241,751,376],{"class":269},[241,753,754],{"class":243,"line":251},[241,755,757],{"emptyLinePlaceholder":756},true,"\n",[241,759,760,764,768,772,775,777,780,783],{"class":243,"line":273},[241,761,763],{"class":762},"sbsja","const",[241,765,767],{"class":766},"sfCm-"," mapRows",[241,769,771],{"class":770},"smGrS"," =",[241,773,774],{"class":269}," ()",[241,776,280],{"class":770},[241,778,729],{"class":779},"sbgvK",[241,781,782],{"class":762}," =>",[241,784,313],{"class":269},[241,786,787,790,794,796,799,802,805],{"class":243,"line":305},[241,788,789],{"class":762},"  const",[241,791,793],{"class":792},"s_hVV"," store",[241,795,771],{"class":770},[241,797,798],{"class":770}," new",[241,800,801],{"class":261}," Map",[241,803,804],{"class":276},"()",[241,806,376],{"class":269},[241,808,809,812],{"class":243,"line":316},[241,810,811],{"class":254},"  return",[241,813,313],{"class":269},[241,815,816,819,821,823],{"class":243,"line":361},[241,817,818],{"class":276},"    client",[241,820,280],{"class":269},[241,822,793],{"class":265},[241,824,825],{"class":269},",\n",[241,827,828,831,833,836,839,843,845,847,849,852,855,857,859,861],{"class":243,"line":367},[241,829,830],{"class":261},"    get",[241,832,280],{"class":269},[241,834,835],{"class":762}," async",[241,837,838],{"class":269}," (",[241,840,842],{"class":841},"s99_P","key",[241,844,373],{"class":269},[241,846,782],{"class":762},[241,848,793],{"class":265},[241,850,851],{"class":269},".",[241,853,854],{"class":261},"get",[241,856,266],{"class":276},[241,858,842],{"class":265},[241,860,373],{"class":276},[241,862,825],{"class":269},[241,864,866,869,871,873,875,877,879,881,883,885,888,890,892,894],{"class":243,"line":865},8,[241,867,868],{"class":261},"    has",[241,870,280],{"class":269},[241,872,835],{"class":762},[241,874,838],{"class":269},[241,876,842],{"class":841},[241,878,373],{"class":269},[241,880,782],{"class":762},[241,882,793],{"class":265},[241,884,851],{"class":269},[241,886,887],{"class":261},"has",[241,889,266],{"class":276},[241,891,842],{"class":265},[241,893,373],{"class":276},[241,895,825],{"class":269},[241,897,899,902,904,906,908,910,912,915,917,919,921,923,925,928,930,932,934,936,938,941],{"class":243,"line":898},9,[241,900,901],{"class":261},"    set",[241,903,280],{"class":269},[241,905,835],{"class":762},[241,907,838],{"class":269},[241,909,842],{"class":841},[241,911,337],{"class":269},[241,913,914],{"class":841}," row",[241,916,373],{"class":269},[241,918,782],{"class":762},[241,920,283],{"class":269},[241,922,793],{"class":265},[241,924,851],{"class":269},[241,926,927],{"class":261},"set",[241,929,266],{"class":276},[241,931,842],{"class":265},[241,933,337],{"class":269},[241,935,914],{"class":265},[241,937,373],{"class":276},[241,939,940],{"class":269},";",[241,942,302],{"class":269},[241,944,946,949,951,953,955,957,959,961,963,965,968,970,972,974],{"class":243,"line":945},10,[241,947,948],{"class":261},"    delete",[241,950,280],{"class":269},[241,952,835],{"class":762},[241,954,838],{"class":269},[241,956,842],{"class":841},[241,958,373],{"class":269},[241,960,782],{"class":762},[241,962,793],{"class":265},[241,964,851],{"class":269},[241,966,967],{"class":261},"delete",[241,969,266],{"class":276},[241,971,842],{"class":265},[241,973,373],{"class":276},[241,975,825],{"class":269},[241,977,979,982,984,986,988,990,992,995,998,1000,1003,1006],{"class":243,"line":978},11,[241,980,981],{"class":261},"    all",[241,983,280],{"class":269},[241,985,835],{"class":762},[241,987,774],{"class":269},[241,989,782],{"class":762},[241,991,345],{"class":276},[241,993,994],{"class":770},"...",[241,996,997],{"class":265},"store",[241,999,851],{"class":269},[241,1001,1002],{"class":261},"values",[241,1004,1005],{"class":276},"()]",[241,1007,825],{"class":269},[241,1009,1011],{"class":243,"line":1010},12,[241,1012,1013],{"class":269},"  };\n",[241,1015,1017],{"class":243,"line":1016},13,[241,1018,1019],{"class":269},"};\n",[241,1021,1023],{"class":243,"line":1022},14,[241,1024,757],{"emptyLinePlaceholder":756},[241,1026,1028,1031,1033,1036,1038,1040,1042,1044,1046,1048,1050,1052,1054,1056,1059,1062,1064,1066,1069,1071,1074,1076,1078,1080,1082,1084,1087],{"class":243,"line":1027},15,[241,1029,1030],{"class":265},"Sources",[241,1032,851],{"class":269},[241,1034,1035],{"class":261},"register",[241,1037,266],{"class":265},[241,1039,299],{"class":291},[241,1041,550],{"class":295},[241,1043,299],{"class":291},[241,1045,337],{"class":269},[241,1047,774],{"class":269},[241,1049,280],{"class":770},[241,1051,736],{"class":779},[241,1053,782],{"class":762},[241,1055,838],{"class":265},[241,1057,1058],{"class":269},"{",[241,1060,1061],{"class":276}," storageFactory",[241,1063,280],{"class":269},[241,1065,721],{"class":261},[241,1067,1068],{"class":265},"(mapRows)",[241,1070,337],{"class":269},[241,1072,1073],{"class":276}," name",[241,1075,280],{"class":269},[241,1077,292],{"class":291},[241,1079,550],{"class":295},[241,1081,299],{"class":291},[241,1083,739],{"class":269},[241,1085,1086],{"class":265},"))",[241,1088,376],{"class":269},[199,1090,1091,1092,1095,1096,1099,1100,1103,1104,1107,1108,1111],{},"C'est ",[203,1093,1094],{},"@fougere\u002Fadapter-memory"," en entier. Le fait qu'",[203,1097,1098],{},"all()"," lise tout est ce qui borne une\nsource sur fichiers : ",[203,1101,1102],{},"list"," avec un ",[203,1105,1106],{},"where"," ou un ",[203,1109,1110],{},"orderBy"," filtre en mémoire, ce qui est\njuste pour des lignes gardées pour leur durabilité et faux sur un chemin de lecture chaud.",[212,1113,1115],{"id":1114},"lire-à-travers","Lire à travers",[199,1117,1118,1119,1125,1126,1129,1130,1133],{},"Les lectures par clé (",[390,1120,1122],{"href":1121},"\u002Ffr\u002Fdocs\u002Fbusiness\u002Fstorage#lire-un-ensemble-pas-une-ligne-%C3%A0-la-fois",[203,1123,1124],{},"findByKeys","\net son dual) ",[223,1127,1128],{},"enrichissent"," une page : « je tiens ces lignes, donne-moi les liées ». Elles\nne peuvent pas en ",[223,1131,1132],{},"sélectionner"," une. Filtrer, trier, paginer ou compter de l'autre côté\ns'effondre en lisant ce côté entier — et « mes prêts, livre le plus récent d'abord »\ntraverse.",[199,1135,1136,1137,1140],{},"C'est ce que ",[203,1138,1139],{},"@fougere\u002Fadapter-duckdb"," ferme. Une Frond déclare ce qu'elle lit :",[232,1142,1144],{"className":234,"code":1143,"language":236,"meta":237,"style":237},"\u002F\u002F fronds\u002Flibrary\u002Ffrond.config.ts\nexport default defineFrond({\n  reads: ['Loan', 'Book'],\n});\n",[203,1145,1146,1151,1164,1193],{"__ignoreMap":237},[241,1147,1148],{"class":243,"line":244},[241,1149,1150],{"class":247},"\u002F\u002F fronds\u002Flibrary\u002Ffrond.config.ts\n",[241,1152,1153,1155,1157,1160,1162],{"class":243,"line":251},[241,1154,255],{"class":254},[241,1156,258],{"class":254},[241,1158,1159],{"class":261}," defineFrond",[241,1161,266],{"class":265},[241,1163,270],{"class":269},[241,1165,1166,1169,1171,1173,1175,1178,1180,1182,1184,1186,1188,1191],{"class":243,"line":273},[241,1167,1168],{"class":276},"  reads",[241,1170,280],{"class":269},[241,1172,345],{"class":265},[241,1174,299],{"class":291},[241,1176,1177],{"class":295},"Loan",[241,1179,299],{"class":291},[241,1181,337],{"class":269},[241,1183,292],{"class":291},[241,1185,350],{"class":295},[241,1187,299],{"class":291},[241,1189,1190],{"class":265},"]",[241,1192,825],{"class":269},[241,1194,1195,1197,1199],{"class":243,"line":305},[241,1196,370],{"class":269},[241,1198,373],{"class":265},[241,1200,376],{"class":269},[199,1202,1203,1204,1207,1208,1211,1212,1214],{},"Le déclarer est ce qui rend ",[203,1205,1206],{},"Reads"," injectable, et cela ",[223,1209,1210],{},"borne aussi ce qui est\nattaché"," : une source qui ne tient aucune de ces entités n'est jamais ouverte, donc ses\ntables n'existent pas dans la connexion. ",[203,1213,209],{}," peut nommer n'importe quelle entité de\nl'application, pas seulement celles de la Frond.",[232,1216,1218],{"className":234,"code":1217,"language":236,"meta":237,"style":237},"export default class LibraryHandler {\n  constructor(private reads: Reads) {}\n\n  async loansByLanguage() {\n    return this.reads.read(LoansByLanguage)`\n      select b.language, count(*) as loans\n      from ${Loan} l join ${Book} b on b.id = l.book_id\n      group by b.language\n      order by b.language`;\n  }\n}\n",[203,1219,1220,1234,1257,1261,1274,1303,1308,1332,1337,1347,1352],{"__ignoreMap":237},[241,1221,1222,1224,1226,1229,1232],{"class":243,"line":244},[241,1223,255],{"class":254},[241,1225,258],{"class":254},[241,1227,1228],{"class":762}," class",[241,1230,1231],{"class":779}," LibraryHandler",[241,1233,313],{"class":269},[241,1235,1236,1239,1241,1244,1247,1249,1252,1254],{"class":243,"line":251},[241,1237,1238],{"class":762},"  constructor",[241,1240,266],{"class":269},[241,1242,1243],{"class":762},"private",[241,1245,1246],{"class":841}," reads",[241,1248,280],{"class":770},[241,1250,1251],{"class":779}," Reads",[241,1253,373],{"class":269},[241,1255,1256],{"class":269}," {}\n",[241,1258,1259],{"class":243,"line":273},[241,1260,757],{"emptyLinePlaceholder":756},[241,1262,1263,1266,1270,1272],{"class":243,"line":305},[241,1264,1265],{"class":762},"  async",[241,1267,1269],{"class":1268},"sVXei"," loansByLanguage",[241,1271,804],{"class":269},[241,1273,313],{"class":269},[241,1275,1276,1279,1283,1285,1288,1290,1293,1295,1298,1300],{"class":243,"line":316},[241,1277,1278],{"class":254},"    return",[241,1280,1282],{"class":1281},"s39Yj"," this",[241,1284,851],{"class":269},[241,1286,1287],{"class":265},"reads",[241,1289,851],{"class":269},[241,1291,1292],{"class":261},"read",[241,1294,266],{"class":276},[241,1296,1297],{"class":265},"LoansByLanguage",[241,1299,373],{"class":276},[241,1301,1302],{"class":291},"`\n",[241,1304,1305],{"class":243,"line":361},[241,1306,1307],{"class":295},"      select b.language, count(*) as loans\n",[241,1309,1310,1313,1316,1318,1320,1323,1325,1327,1329],{"class":243,"line":367},[241,1311,1312],{"class":295},"      from ",[241,1314,1315],{"class":291},"${",[241,1317,1177],{"class":265},[241,1319,370],{"class":291},[241,1321,1322],{"class":295}," l join ",[241,1324,1315],{"class":291},[241,1326,350],{"class":265},[241,1328,370],{"class":291},[241,1330,1331],{"class":295}," b on b.id = l.book_id\n",[241,1333,1334],{"class":243,"line":865},[241,1335,1336],{"class":295},"      group by b.language\n",[241,1338,1339,1342,1345],{"class":243,"line":898},[241,1340,1341],{"class":295},"      order by b.language",[241,1343,1344],{"class":291},"`",[241,1346,376],{"class":269},[241,1348,1349],{"class":243,"line":945},[241,1350,1351],{"class":269},"  }\n",[241,1353,1354],{"class":243,"line":978},[241,1355,1356],{"class":269},"}\n",[199,1358,1359],{},"Deux choses sont tenues par les types plutôt que demandées :",[1361,1362,1363,1386],"ul",{},[1364,1365,1366,1369,1370,1374,1375,1378,1379,1382,1383,851],"li",{},[223,1367,1368],{},"La forme nomme la réponse."," Le tag n'est atteignable qu'",[1371,1372,1373],"em",{},"à travers"," une forme, donc il\nn'y a pas de requête sans sortie déclarée. Un ",[203,1376,1377],{},"select *"," brut renverrait les champs que\n",[203,1380,1381],{},"boundary.out: 'closed'"," promet de ne jamais laisser sortir ; la projection est la\nclôture. Une colonne que la forme ne nomme pas ne sort jamais, et une forme qui déclare un\nchamp que la requête ne répond pas échoue par son nom plutôt que de rendre des ",[203,1384,1385],{},"null",[1364,1387,1388,1391,1392,1395,1396,1399,1400,1402],{},[223,1389,1390],{},"Seule une entité peut être interpolée."," ",[203,1393,1394],{},"${Book}"," devient ",[203,1397,1398],{},"\"archive\".\"books\""," — l'alias\net la table depuis une seule déclaration. Nommer une entité hors de ",[203,1401,209],{}," est refusé,\nparce que sa table n'est réellement pas dans cette connexion.",[199,1404,1405,1406,1409,1410,1413],{},"Chaque attache est en ",[203,1407,1408],{},"READ_ONLY",", et c'est le moteur qui l'impose. Cette porte lit à\ntravers tout le stockage de l'application : elle est strictement plus atteignable que\n",[203,1411,1412],{},"storage.client"," — qui garde au moins la portée de son entité — et une écriture par là ne\nrencontrerait aucun juge.",[212,1415,1417],{"id":1416},"ce-que-ce-nest-pas","Ce que ce n'est pas",[199,1419,1420,1423],{},[223,1421,1422],{},"Pas un constructeur de requêtes."," Un builder multi-sources serait un Calcite en\nTypeScript, et il promettrait une composabilité que les sources n'ont pas. La requête reste\ndu SQL. Ce que Fougere apporte, ce sont les trois dérivations qu'une requête écrite à la\nmain dupliquerait : où vit chaque entité, comment s'appellent sa table et ses colonnes, et\nla forme de la réponse.",[199,1425,1426,1429],{},[223,1427,1428],{},"Pas le chemin de lecture ordinaire."," Mesuré avant d'écrire quoi que ce soit : à la taille\nd'une page, DuckDB est ~100× plus lent que deux lectures indexées — environ 7 ms de plancher\npar requête. À utiliser là où une question traverse vraiment, jamais pour aller chercher une\npage.",[199,1431,1432,1433,1436,1437,1440,1441,851],{},"Rien n'est copié. Attacher Postgres pousse le filtre chez lui — ",[203,1434,1435],{},"Filters: lang='fr'","\nl'atteint sur 100 000 lignes — donc une vraie base est interrogée là où elle est. Pour une\nsource ",[223,1438,1439],{},"sans aucune"," algèbre (une API HTTP, le catalogue d'un partenaire), la réponse est\n",[390,1442,1444],{"href":1443},"\u002Ffr\u002Fdocs\u002Fconcepts\u002Fthe-base#mirror--une-copie-locale-de-lignes-quon-ne-peut-pas-interroger",[203,1445,1446],{},"Mirror",[1448,1449,1450],"warning",{},[199,1451,1452,1455],{},[223,1453,1454],{},"Il n'y a aucune liaison de paramètre."," Une valeur va dans le texte de requête que vous\nécrivez : ne construisez donc pas ce texte à partir d'une entrée utilisateur. Filtrez le\nrésultat, ou gardez la partie variable hors de la chaîne.",[212,1457,1459],{"id":1458},"limites","Limites",[1361,1461,1462,1483,1494],{},[1364,1463,1464,1467,1468,1471,1472,1475,1476,1479,1480,851],{},[223,1465,1466],{},"SQL Server ne peut pas être attaché"," — il n'existe pas d'extension ",[203,1469,1470],{},"sqlserver"," pour\nDuckDB. Les moteurs attachables sont ",[203,1473,1474],{},"sqlite",", ",[203,1477,1478],{},"postgres"," et ",[203,1481,1482],{},"mysql",[1364,1484,1485,1486,1489,1490,1493],{},"Une source doit dire ",[203,1487,1488],{},"path"," ou ",[203,1491,1492],{},"attach"," : on indique à DuckDB quoi ouvrir, et une base en\nmémoire à lui ne tiendrait aucune de vos lignes.",[1364,1495,1496,1497,1499],{},"Un ",[203,1498,209],{}," qu'aucun boot ne peut servir est signalé plutôt qu'ignoré.",[1501,1502,1503],"style",{},"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}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 .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--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 .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 .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sfCm-, html code.shiki .sfCm-{--shiki-light:#90A4AE;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--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 .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s99_P, html code.shiki .s99_P{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .sVXei, html code.shiki .sVXei{--shiki-light:#E53935;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":237,"searchDepth":251,"depth":251,"links":1505},[1506,1507,1510,1511,1512],{"id":214,"depth":251,"text":215},{"id":407,"depth":251,"text":408,"children":1508},[1509],{"id":685,"depth":273,"text":686},{"id":1114,"depth":251,"text":1115},{"id":1416,"depth":251,"text":1417},{"id":1458,"depth":251,"text":1459},"Où vivent les lignes d'une entité, et comment une seule requête lit à travers plusieurs endroits sans en copier aucun.","md",{},{"title":170,"description":1513},"5Se7U8YfQLNO4Cacpiyx24eTiXKqoPbIPLUcSctO3bg",1788598419556]