[{"data":1,"prerenderedAt":409},["ShallowReactive",2],{"navigation":3,"\u002Fconcepts\u002Farchitecture":103,"\u002Fconcepts\u002Farchitecture-surround":404},[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":16,"body":105,"description":397,"extension":398,"links":399,"meta":400,"navigation":401,"path":17,"seo":402,"stem":18,"__hash__":403},"docs\u002F02.concepts\u002Farchitecture.md",{"type":106,"value":107,"toc":387},"minimark",[108,112,117,128,132,201,205,245,248,252,277,284,288,371,375,378],[109,110,111],"p",{},"OpenSya Persistence separates the description of a data model from the execution of database operations.",[113,114,116],"h2",{"id":115},"runtime-overview","Runtime overview",[118,119,125],"pre",{"className":120,"code":122,"language":123,"meta":124},[121],"language-text","Application service\n        │\n        ▼\n    QueryEngine\n   ┌────┼──────────────┐\n   ▼    ▼              ▼\nRegistry Hooks   RelationResolver\n        │              │\n        └──────┬───────┘\n               ▼\n       DatabaseAdapter\n               │\n               ▼\n            Database\n","text","",[126,127,122],"code",{"__ignoreMap":124},[113,129,131],{"id":130},"components","Components",[133,134,135,150,156,162,168,175,184,190,196],"accordion",{},[136,137,139],"accordion-item",{"icon":24,"label":138},"MetadataRegistry",[109,140,141,142,145,146,149],{},"Stores ",[126,143,144],{},"TableMetadata",", rejects duplicate logical names, validates the complete schema, and becomes immutable after ",[126,147,148],{},"lock()",".",[136,151,153],{"icon":29,"label":152},"QueryEngine",[109,154,155],{},"Provides application-facing reads and mutations. It coordinates defaults, hooks, validation, transactions, safe targeting, and relation population.",[136,157,159],{"icon":61,"label":158},"HooksRegistry",[109,160,161],{},"Stores ordered callbacks for create, update, and delete operations. Before hooks may transform data; after hooks run before the transaction commits.",[136,163,165],{"icon":76,"label":164},"RelationResolver",[109,166,167],{},"Resolves explicitly requested direct relations by batching key values and grouping related rows in memory.",[136,169,172],{"icon":170,"label":171},"i-tabler-database-cog","DatabaseAdapter",[109,173,174],{},"Defines the storage contract: reads, inserts, updates, deletes, transactions, runtime table construction, and schema introspection.",[136,176,178],{"icon":81,"label":177},"ConsistencyChecker",[109,179,180,181,149],{},"Compares declared metadata with the schema returned by ",[126,182,183],{},"DatabaseAdapter.introspect()",[136,185,187],{"icon":56,"label":186},"FieldSerializer",[109,188,189],{},"Removes hidden and context-sensitive fields from base entities and populated relations.",[136,191,193],{"icon":41,"label":192},"AuditManager",[109,194,195],{},"Produces before\u002Fafter snapshots and field changes through a transaction-scoped writer.",[136,197,198],{"icon":51,"label":48},[109,199,200],{},"Collects business events inside application transactions, stores them in an outbox, and publishes them through an injectable processor.",[113,202,204],{"id":203},"read-path","Read path",[206,207,209,214,220,224,227,231,238,242],"steps",{"level":208},"3",[210,211,213],"h3",{"id":212},"resolve-table-metadata","Resolve table metadata",[109,215,216,217,149],{},"Unknown logical table names fail through ",[126,218,219],{},"registry.getOrThrow()",[210,221,223],{"id":222},"query-the-adapter","Query the adapter",[109,225,226],{},"The engine forwards filters, sorting, limit, and offset.",[210,228,230],{"id":229},"populate-requested-relations","Populate requested relations",[109,232,233,234,237],{},"When ",[126,235,236],{},"populate"," is present, the resolver loads each named direct relation.",[210,239,241],{"id":240},"serialize-and-return-typed-data","Serialize and return typed data",[109,243,244],{},"Hidden and contextual fields are removed, including inside populated relations.\nThe entity type is inferred from the registered table metadata.",[109,246,247],{},"Reads do not run lifecycle hooks and are not automatically transactional.",[113,249,251],{"id":250},"mutation-path","Mutation path",[253,254,255,263,270],"tabs",{},[256,257,260],"tab",{"icon":258,"label":259},"i-tabler-plus","Create",[109,261,262],{},"Defaults → before hooks → known-field check → complete validation → insert → after hooks.",[256,264,267],{"icon":265,"label":266},"i-tabler-edit","Update",[109,268,269],{},"Safe-filter check → load current rows → before hooks → merge and validate touched fields → update → after hooks.",[256,271,274],{"icon":272,"label":273},"i-tabler-trash","Delete",[109,275,276],{},"Safe-filter check → resolve target when needed → before hooks → delete → after hooks.",[109,278,279,280,283],{},"All mutation steps execute inside ",[126,281,282],{},"adapter.transaction()",". When configured,\naudit entries use that same adapter. Application transactions additionally\nflush collected Domain Events to the outbox before the outer commit.",[113,285,287],{"id":286},"logical-and-physical-identifiers","Logical and physical identifiers",[289,290,291,307],"table",{},[292,293,294],"thead",{},[295,296,297,301,304],"tr",{},[298,299,300],"th",{},"Property",[298,302,303],{},"Used by",[298,305,306],{},"Example",[308,309,310,326,341,356],"tbody",{},[295,311,312,318,321],{},[313,314,315],"td",{},[126,316,317],{},"TableMetadata.name",[313,319,320],{},"Engine and adapter lookup",[313,322,323],{},[126,324,325],{},"users",[295,327,328,333,336],{},[313,329,330],{},[126,331,332],{},"TableMetadata.collectionName",[313,334,335],{},"Physical table construction and consistency matching",[313,337,338],{},[126,339,340],{},"app_users",[295,342,343,348,351],{},[313,344,345],{},[126,346,347],{},"ColumnMetadata.name",[313,349,350],{},"Entities, filters, and sorting",[313,352,353],{},[126,354,355],{},"createdAt",[295,357,358,363,366],{},[313,359,360],{},[126,361,362],{},"ColumnMetadata.columnName",[313,364,365],{},"PostgreSQL column construction and consistency matching",[313,367,368],{},[126,369,370],{},"created_at",[113,372,374],{"id":373},"adapter-independence","Adapter independence",[109,376,377],{},"The Query Engine does not import Drizzle types. A custom adapter can target another store if it preserves the contract and semantics.",[379,380,384],"callout",{"color":381,"icon":382,"variant":383},"primary","i-tabler-shield-check","subtle",[109,385,386],{},"A custom adapter should preserve non-empty mutation filters, field validation, transactional callbacks, predictable return values, and read-only introspection.",{"title":124,"searchDepth":388,"depth":389,"links":390},1,2,[391,392,393,394,395,396],{"id":115,"depth":389,"text":116},{"id":130,"depth":389,"text":131},{"id":203,"depth":389,"text":204},{"id":250,"depth":389,"text":251},{"id":286,"depth":389,"text":287},{"id":373,"depth":389,"text":374},"How metadata, execution services, and database adapters work together.","md",null,{},{"icon":19},{"title":16,"description":397},"i09UqD7u1L_H1pEzgsNLdWL_lrepZF2SqcFUeRRIICg",[405,407],{"title":5,"path":6,"stem":7,"description":406,"icon":8,"children":-1},"Create a typed OpenSya Persistence runtime with PostgreSQL and Drizzle.",{"title":21,"path":22,"stem":23,"description":408,"icon":24,"children":-1},"Define the domain model once and preserve it through the typed runtime.",1783784235117]