尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

native Record Store 示例解读:无需文件路径与 SQL 的引擎级持久化存储

native Record Store 示例解读:无需文件路径与 SQL 的引擎级持久化存储 桌面应用跨平台【免费下载链接】nativeToolkit for building native desktop apps项目地址https://gitcode.com/gh_mirrors/ze/native点击查看免费下载本文以 examples/record-store 官方示例为骨架深入讲解 native 项目中 Tier 2 record store独立字节记录存储的完整用法如何在app.zon中声明storecapability、如何通过Cmd.store五个命令scan / setMany / get / set / delete与Msg回环完成增删改查、以及引擎层如何以 SQLite 为底座实现原子批量写入与前缀扫描。读完本文你将掌握一套不接触文件路径、不手写 SQL的本地持久化开发范式并能在 record-store/src/core.ts 与 src/runtime/record_store.zig 的源码对照中验证其底层原理。一、示例概览一次完整的记录生命周期Record Store 是一个默认的 TypeScript Native markup 应用用来演示 Tier 2 record store 的全部能力。根据 examples/record-store/README.md该应用在initialModel阶段加载一个前缀页prefix page然后原子化地种子化seed若干条记录读取并更新其中一条记录最后删除它——全程不处理文件路径也不写一条 SQL 语句。运行方式与仓库内其他示例保持一致仅两条命令native test native run其中native test用于编译并运行该示例的测试native run用于构建并启动桌面应用窗口。由于 TypeScript 核心在 native CLI 侧是无node_modules依赖的见 examples/record-store/package.json 中的描述the native CLI builds without node_modulesnative-sdk/core仅作为编辑器侧的开发依赖存在。二、能力声明storecapability 与 SQLite 的按需裁剪record store 的启用完全由app.zon清单控制。查看 examples/record-store/app.zon.{ .id dev.native_sdk.record_store, .name record-store, .display_name Record Store, .description A TypeScript and Native markup example of the engine-owned record store., .version 0.1.0, .platforms .{macos}, .permissions .{ view, command }, .capabilities .{ native_views, gpu_surfaces, store }, ... }关键一行是.capabilities .{ native_views, gpu_surfaces, store }。README 明确说明应用声明了storecapability构建时不带该 capability 的应用会自动裁掉 SQLite 引擎builds without that capability shed the SQLite engine。这意味着 record store 不是运行时随手可用的基础设施而是一项需要显式声明、由引擎按需编译进产物并持有数据库文件的能力。从源码看引擎侧的store效果由 src/runtime/effects.zig 引入record_store模块并提供独立的效果容量const record_store import(record_store.zig); // ... /// Record-store effects have their own capacity: a large batch or a busy pub const max_store_effects: usize 16;即 record store 效果拥有独立于文件/网络等通用效果的 16 个请求槽位不会挤占其他 worker 的额度。同时引擎还从 src/runtime/record_store.zig 导出若干关键常量约束每条记录与每批写入的边界详见下文第五节。此外app.zon还声明了窗口布局680×480最小 520×360、GPU surface 视图Metal 后端、bgra8_unorm像素格式、srgb色彩空间、垂直同步开启以及安全策略仅允许zero://app与zero://inline来源、拒绝外部链接展示了一个完整的 native 应用清单应有的结构。三、TypeScript 核心Model / Msg / Cmd 的数据流示例的 TypeScript 核心位于 examples/record-store/src/core.ts其注释点明了设计原则every database interaction is inert Cmd data and every observation returns through an ordinary Msg after the model commits——所有数据库交互都是惰性inert的 Cmd 数据所有观测结果都在模型提交之后以普通 Msg 形式返回。核心数据结构export interface Model { readonly recordCount: number; readonly current: Uint8Array; readonly present: boolean; readonly status: Uint8Array; }Msg采用可辨识联合discriminated union写法全部以kind区分seed/seeded/load/loaded/save/saved/remove/removed/refresh/scanned/store_failed。其中seeded、loaded、saved、removed、scanned、store_failed是存储效果的回传消息因此被列入viewUnbound常量表示这些消息到达时视图无需等待绑定。启动时initialModel立刻发起一次前缀扫描作为初始加载export function initialModel(): [Model, CmdMsg] { return [ { recordCount: 0, current: new Uint8Array(0), present: false, status: utf8Bytes(Loading the drafts/ prefix…), }, Cmd.store.scan(drafts/, { limit: 16 }, { key: scan-drafts, ok: scanned, err: store_failed, }), ]; }这里可以看到Cmd.store.scan的签名形态第一个参数是前缀字符串第二个参数是选项对象limit第三个参数是回传配置key为调用方自定义的标识ok/err为成功后派发到update的消息种类。所有字节内容统一以Uint8Array承载字符串则用utf8Bytes(...)转换。四、五个存储命令的完整用法示例以五个按钮对应五个命令构成一次完整的记录生命周期。下面结合 core.ts 逐一展开。1. 前缀扫描Cmd.store.scan用于列出某个前缀下的记录并统计数量。在seed、refresh、removed等消息处理中都会重新发起扫描Cmd.store.scan(drafts/, { limit: 16 }, { key: scan-drafts, ok: scanned, err: store_failed, }),扫描结果msg.page是一个Uint8Array其中前 4 字节以小端序编码了记录数量示例用pageCount函数手工解码page[0] page[1]*256 page[2]*65536 page[3]*16777216随后才是页面数据。引擎侧默认扫描上限为 100 条、硬上限 256 条见 src/runtime/record_store.zig 的default_scan_limit 100、max_scan_limit 256示例传入limit: 16属于保守取值。2. 原子批量写入Cmd.store.setManyseed消息一次性写入三条记录且整批原子提交——要么全部成功要么全部不生效Cmd.store.setMany([ [ACTIVE_KEY, utf8Bytes(A saved draft from the record store)], [drafts/archive/1, utf8Bytes(First archived draft)], [drafts/archive/2, utf8Bytes(Second archived draft)], ], { key: seed-drafts, ok: seeded, err: store_failed }),其中ACTIVE_KEY drafts/current。批量写入的原子性由引擎层测试明确保证src/runtime/effects_store_tests.zig 中test record-store effects apply setMany atomically and page prefix scans直接验证了 setMany 的原子提交与前缀页扫描的正确性。引擎对批量的大小也有硬约束最多 64 条、总字节不超过 8 MiBmax_batch_entries 64、max_batch_bytes 8 * 1024 * 1024。3. 读取单条Cmd.store.getload消息读取drafts/currentCmd.store.get(ACTIVE_KEY, { key: load-current, ok: loaded, err: store_failed, }),结果msg.result的首字节是存在标志位1表示记录存在后续字节即记录内容0表示记录不存在应用据此把present置为false并显示 Record is absent。4. 写入单条Cmd.store.setsave消息覆盖写入drafts/current写入内容与其他记录完全独立Cmd.store.set( ACTIVE_KEY, utf8Bytes(Updated independently of every other record), { key: save-current, ok: saved, err: store_failed }, ),写入成功后saved消息应用立即回读一次再次发起get用结果刷新界面形成写后读闭环。5. 删除单条Cmd.store.deleteremove消息删除drafts/currentCmd.store.delete(ACTIVE_KEY, { key: delete-current, ok: removed, err: store_failed, }),删除成功后removed消息清空本地展示并重新扫描前缀页保持recordCount徽标与真实数据一致。任何命令的err消息都会统一落入store_failed分支把错误原因直接写入status显示在状态栏。此外测试还验证了命令时序的语义src/runtime/effects_store_tests.zig 中test a synchronous get in the same command walk observes the preceding write证明同一轮命令内先写后读能够立即观察到结果这为保存后立刻回读这类业务模式提供了引擎级保证。五、底层实现字节记录、前缀键与 SQLite 引擎record store 的定位是engine-owned app-data database引擎持有的应用数据数据库由引擎负责创建、打开与持有。UI 上 examples/record-store/src/app.native 的说明文字也印证了这一点关闭并重新打开应用值依然保留在引擎拥有的数据库中。从 src/runtime/record_store.zig 可以看到实现关键点键值均为原始字节键最大 512 字节max_key_bytes 512值最大 1 MiBmax_value_bytes 1024 * 1024单条结果上限max_result_bytes max_value_bytes 2*max_key_bytes 32引擎维护独立的读写连接write_db与可选的read_db见Store结构读连接按需打开避免长事务阻塞读路径底层持久化基于 src/runtime/sqlite_engine.zig 封装的 SQLite 连接sqlite.Connection.open因此不使用 SQL是指应用层不暴露 SQL引擎内部仍以 SQLite 作为存储底座提供open(data_dir)与openMemory()两条打开路径前者用于真实应用数据目录持久化后者供测试使用内存库。由于记录键是任意字节前缀串drafts/ 这类带斜杠的层级键天然支持前缀扫描从而实现目录式的组织方式而无需文件系统介入——这正是示例把记录放在drafts/与drafts/archive/下的原因。六、视图层Native markup 的五个操作按钮examples/record-store/src/app.native 用声明式 Native markup 搭建界面顶部标题与说明、一块展示drafts/current内容的面板、一个显示recordCount的徽标以及一行五个按钮row gap10 button variantprimary on-pressseedSeed atomically/button button variantoutline on-pressloadLoad current/button button variantoutline on-presssaveSave current/button button variantdestructive on-pressremoveDelete current/button button variantghost on-pressrefreshRefresh count/button /rowon-press直接映射到 core 中对应的Msg.kindseed / load / save / remove / refresh按下按钮即派发消息界面用if test{present}/else在有记录与无记录两种状态间切换底部status-bar{status}/status-bar展示操作进度与错误信息。这一层完全不感知存储细节只消费 Model 中的纯数据——视图与存储彻底解耦。七、小结何时使用 record storeRecord Store 示例展示了 native 中一条清晰的持久化路径在app.zon声明storecapability → TypeScript 核心通过Cmd.store.*派发惰性命令 → 引擎在独立效果槽位max_store_effects 16中以 SQLite 为底座执行 → 结果以 Msg 形式在模型提交后回传 → Native markup 仅渲染 Model。开发者全程不需要文件路径也不需要写 SQL只需约定字节键的命名如drafts/前缀即可获得原子批量写入、前缀扫描和写后读一致性的保证。如果想深入验证文中涉及的常量与测试语义推荐按以下路径继续阅读示例清单examples/record-store/app.zon示例核心examples/record-store/src/core.ts示例视图examples/record-store/src/app.native引擎存储实现与边界常量src/runtime/record_store.zig效果槽位与容量定义src/runtime/effects.zig原子性与命令时序测试src/runtime/effects_store_tests.zig赞分享桌面应用跨平台【免费下载链接】nativeToolkit for building native desktop apps项目地址https://gitcode.com/gh_mirrors/ze/native点击查看免费下载相关推荐Activepieces 键值存储Key-Value Store深度解析持久化、作用域隔离与引擎调用链路Activepieces 键值存储Key Value Store深度解析持久化、作用域隔离与引擎调用链路 本指南围绕 Activepieces 开源仓库中工作流自动化低代码AI 应用人工智能AI AgentMCP 服务后端前端深入解读 RocksDB面向闪存与内存的嵌入式持久化键值存储引擎深入解读 RocksDB面向闪存与内存的嵌入式持久化键值存储引擎 RocksDB 是一个可嵌入、持久化的键值存储库其核心定位是作为快速键值服务器的基础构建块数据库KV存储嵌入式数据库存储如何高效使用EdgeDB存储引擎PostgreSQL数据持久化技术实现指南如何高效使用EdgeDB存储引擎PostgreSQL数据持久化技术实现指南 EdgeDB是一个基于PostgreSQL构建的现代数据库系统它通过创新的数据模数据库图数据库关系型数据库上一篇Vin象棋5分钟打造你的免费AI象棋教练告别手动摆棋烦恼下一篇BenchmarkDotNet的Job配置详解一套代码在.NET、Mono与NativeAOT间快速对比性能创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表