☰
Lovefield 规范导读:Web 应用关系型数据库引擎的设计目标、工作流与 API 风格
2026/10/7 9:24:26 网站建设 项目流程
  • 关系型数据库
  • 数据库
  • 前端

【免费下载链接】lovefield

Lovefield is a relational database for web apps. Written in JavaScript, works cross-browser. Provides SQL-like APIs that are fast, safe, and easy to use.

项目地址:https://gitcode.com/gh_mirrors/lov/lovefield
点击查看免费下载

Lovefield 是一个面向 Web 应用的关系型查询引擎(relational query engine),以 JavaScript 编写、跨浏览器运行,提供类 SQL 的 API。本文是 Lovefield 官方规范(docs/spec/)的开篇导读,系统梳理其设计目标、基本假设、十项核心需求、两种使用工作流(Grab-and-use 与 Closure 编译器高级优化流程)以及 API 风格约定。读完本文,你将掌握 Lovefield 的设计边界(数据量、SQL 子集、存储方式)、如何从零接入并使用其 Schema Builder 建库,以及为何所有异步 API 均基于 Promise、DDL 与 DML 的同步/异步分工。

1. 设计目标:为 Web 应用提供关系型查询引擎

Lovefield 的定位非常明确:为 Web 应用提供关系型查询引擎(relational query engine for web apps)。它不是传统意义上的"数据库",而是一个运行在浏览器里的查询引擎层——数据持久化委托给浏览器已有的存储技术(如 IndexedDB),查询、索引、约束、事务则由 Lovefield 自身实现。

这一目标决定了它与其他方案的本质区别:相对于纯前端数据容器(如简单的数组或对象存储),Lovefield 提供结构化的表(Table)、列(Column)、索引(Index)、约束(Constraint)与查询计划(Query Plan);相对于服务端数据库,它运行在浏览器环境中,受限于浏览器存储能力与单机资源。

2. 基本假设:Lovefield 适用的场景边界

Lovefield 规范在开篇即明确了三条基本假设,这些假设划定了它的适用范围:

  1. 数据集规模:Lovefield 面向"数据集小于 X(当前上限为 2GB),但大到足以需要一个结构化查询引擎"的数据库。也就是说,它服务于中等规模的数据集——小到不需要服务端数据库,大到纯内存数组难以高效管理。
  2. SQL 子集:Lovefield 只提供 SQL-03 标准的一个有限子集(相关语法 BNF 可参考 SQL-2003-2),并非完整的 SQL 实现。这意味着 JOIN、GROUP BY、聚合等能力是"够用但受限"的,例如多列ROLLUP、CUBE、HAVING均不支持。
  3. 数据安全性责任:Lovefield 使用现有存储技术(如 IndexedDB)在需要时持久化数据。开发者有责任确保任何从 Lovefield 查询引擎访问的数据都被视为"unsafe",并在发送回服务器之前以某种方式进行净化(sanitize)。

第 3 条假设尤其值得注意:Lovefield 不会替你做输入校验或 XSS 防护,它只是数据的存取与查询层,安全边界由使用者自己把控。

3. 十项核心需求:Lovefield 的设计约束清单

规范列出了 Lovefield 必须满足的十项需求,它们直接塑造了库的架构形态,也与仓库中的源码结构一一对应:

#需求对实现的影响(对应仓库证据)
1SQL 类关系查询引擎,覆盖 WebSQL 支持的大部分用例查询构建器与执行引擎,见 lib/query/、lib/proc/
2兼容 Closure compiler:生成的代码与库本身都必须可被其编译全库使用 Closure 风格注解与goog.provide/goog.require,如 lib/schema/builder.js
3兼容 Chrome Apps v2,仅需存储访问权限这直接排除了"持久化 JavaScript 函数再 eval"的自定义索引方案(见下文 Schema 一节)
4可即插即用(Drop-in library)单文件分发即可使用
5可作组件使用提供lf.schema、lf.query、lf.proc等分层命名空间
6可被多种 JS 框架使用:Closure、jQuery、Polymer、AngularJS 等仓库demos/下提供了 jQuery 演示、Polymer 演示、Angular 演示 等
7复制式部署:用户只需把压缩后的 JS 文件拷进项目即可使用即下面"Basic Flow"中的 Grab and use
8使用本库不得产生任何副作用API 全部收敛在lf命名空间内,不污染全局
9跨浏览器:兼容 Chrome、Firefox、Internet Explorer、Safari通过goog.Promise等 polyfill 机制实现,见下文 API 风格
10支持低端设备(低 CPU、低内存,如 HP Chromebook 11)性能与内存占用是索引、结果对象设计的重要考量

需求 2 与需求 3 是理解 Lovefield 技术选型的两把钥匙:Closure 编译器兼容意味着所有代码都带有完整类型注解(这也是仓库源码几乎每个函数都有@param、@return、@constructor、@export注解的原因);Chrome Apps v2 约束则限定了"不能持久化并执行 JavaScript 函数",进而决定了自定义索引的不可能(详见 Schema 一节)。

4. 两种设计工作流:Basic Flow 与 Advanced Flow

4.1 Basic Flow:Grab and use

最基本的使用方式就是"拿来就用"(Grab and use)——复制分发好的压缩 JS 文件到项目,调用lf.schema.create()建库、connect()连接、然后用查询构建器执行 CRUD。仓库中的 todo 演示 就是这种开箱即用流程的完整示例,也是规范指定的 Quick Start 入口。

这种流程对应的就是动态 Schema 创建:直接用 JavaScript API 声明表结构。例如(代码取自 docs/spec/01_schema.md):

// Begin schema creation. var schemaBuilder = lf.schema.create('crdb', 1); schemaBuilder.createTable('Asset'). addColumn('id', lf.Type.STRING). addColumn('asset', lf.Type.STRING). addColumn('timestamp', lf.Type.INTEGER). addPrimaryKey(['id']); // Schema is defined, now connect to the database instance. schemaBuilder.connect().then( function(db) { // Schema is not mutable once the connection to DB has established. });

从源码看,lf.schema.create(dbName, dbVersion)实际是lf.schema.Builder的工厂函数(lib/schema/builder.js#L414-L416),而connect()内部会完成数据库初始化、版本匹配检测、必要时执行升级,最终返回一个实现了lf.Database接口的连接对象(lib/schema/builder.js#L257-L285)。

4.2 Advanced Flow:面向 Closure 编译器高级优化

当项目整体使用 Closure 编译器做高级优化(advanced optimization)编译打包时,推荐采用静态 Schema 流程:

  1. 在 YAML 文件中创建表结构——用声明式文件描述 Schema;
  2. 使用 SPAC(Schema Parser And Code-Generator,Schema 解析器与代码生成器)解析 YAML 并生成 JavaScript 源码——生成带完整 Closure 类型注解的类与函数;
  3. 在代码中使用生成的类/函数——建库、建表对象、构造查询条件都直接引用生成的符号;
  4. 用 Closure 编译器把一切编译合并——Lovefield 核心库与你的代码一起编译。

这条流程的收益在 docs/spec/07_spac.md 中有明确量化:通过 SPAC + Closure 编译,Lovefield 的代码体积可从约 200KB(minimized)降至约 70KB,同时获得更严格的类型检查。代价是 Lovefield 需要被编译进使用者的代码中,而不是单独分发。

SPAC 工具本体位于仓库 spac/ 目录,包括解析器(spac/parser.js)、代码生成器(spac/codegen.js)与命令行入口(spac/lovefield-spac)。它生成的代码包含:一个用于创建数据库实例的静态函数、一个可用于构造查询条件的数据库 Schema 类、以及一个可用于创建查询的数据库实例类。

两种流程的本质区别在于 Schema 的定义方式:动态(JavaScript API)vs 静态(YAML + 代码生成)。两者功能等价,选择依据是是否走 Closure 高级优化编译。

5. API 风格:三大铁律

规范明确了 Lovefield 全部 API 必须遵守的三条风格约定,理解它们等于拿到了阅读整个仓库源码的钥匙。

5.1 Google JS 风格 + Closure 注解

所有 API 与源码必须遵循 Google JavaScript Style Guide,并且必须通过 Closure 编译器编译。这意味着所有 API 与源码都带 Closure 风格注解(@constructor、@export、@param、@return等)。

一个重要的细节是:Closure 将Promise注解为IThenable。Lovefield 使用goog.Promise实现跨浏览器的 Promise 支持,因此继承了IThenable注解——这正是为不支持原生 Promise 的浏览器(如 Internet Explorer 10)提供 polyfill 的基础。

5.2 所有异步 API 均基于 Promise

所有异步 API 都是 Promise 化的。你几乎看不到回调风格 API:connect()、exec()、createTransaction()的begin()/attach()/commit()/rollback()全部返回 Promise 或接受 then 链。这带来一致的异步编程模型:

db.select().from(item).exec().then(function(rows) { // 处理查询结果 });

5.3 DDL 同步、DML 异步

  • 所有 DDL(数据定义语言)API 是同步的:lf.schema.create()、createTable()、addColumn()、addPrimaryKey()等 Schema 构建调用都是同步执行的——这符合"Schema 一旦连接便不可变"的设计。
  • 所有 DML(数据操作语言)API 是异步的:insert()、update()、delete()、select()的exec()都是异步的,返回 Promise。

这条分工从 lib/schema/builder.js 中可见一斑:createTable()直接同步返回TableBuilder并注册表构建器(L293-L303),而connect()则返回IThenable<!lf.proc.Database>(L257)。

6. 深入:Schema Builder 的状态机与校验逻辑

理解lf.schema.Builder的源码实现,有助于把上文的工作流落到实处。从 lib/schema/builder.js 可以看到:

  • Builder 是有状态对象:包含building(构建中)与finalized(已定型)两种状态。Schema 只能在构建状态下修改;一旦通过connect()或getSchema()触发finalize_(),Builder 不再接受任何调用(createTable()会抛出异常 535 "Schema is already finalized")。
  • createTable()返回 TableBuilder 并支持链式调用:addColumn、addPrimaryKey、addForeignKey、addUnique、addNullable、addIndex、persistentIndex全部返回this,形成流畅的链式声明语法(见 lib/schema/table_builder.js)。
  • finalize 阶段执行完整的外键校验:finalize_()内部依次执行checkForeignKeyValidity_()(外键引用的表/列是否存在、类型是否匹配、被引用列是否唯一)、checkForeignKeyChain_()(禁止外键链式引用同一列)、checkFkCycle_()(基于 DFS 检测外键环,异常 533)。也就是说,非法 Schema 会在connect()之前就被拦截。

TableBuilder 内部还会校验:主键列不可同时是外键子列(异常 543)、主键索引不可与显式索引重复(异常 544)、主键列不可标记为 nullable(异常 545)、autoIncrement 只能用于单列整数主键(异常 504/505)、ARRAY_BUFFER与OBJECT类型不可被索引(异常 509)等。

7. 延伸阅读:规范文档地图

本导读对应的完整规范位于 docs/spec/ 目录,推荐按以下顺序阅读:

文档主题
01_schema.mdSchema 定义:命名规则、列类型、约束、索引、静态 Schema
02_data_store.md数据存储:IndexedDB / Memory / Firebase / WebSQL 四种存储
03_life_of_db.md数据库生命周期:初始化、多进程连接、升级、导入导出
04_query.md查询:SELECT/INSERT/UPDATE/DELETE 构建器、参数化查询、观察者
05_transaction.md事务:隐式/显式事务、执行计划、表级锁并发控制
07_spac.mdSPAC:YAML 静态 Schema 与代码生成
08_referential_integrity.md引用完整性:外键 action 与 timing 的详细语义
99_postfix.md附录:实验性特性(如 Bundle Mode)

此外,设计文档位于 docs/dd/,其中 04_query_engine.md 深入讲解查询引擎的物理计划生成与各类 pass(如 push-down selections、index range scan),适合想了解查询引擎内部的读者;docs/dev_setup.md 与 docs/running_tests.md 则介绍了本地开发环境与测试运行方式。

结语

Lovefield 的设计文档以其十项需求勾勒出一个清晰的工程画像:一个面向中等规模数据、以 SQL 子集为接口、以浏览器存储为后端、以 Closure 编译器为工程基线的前端关系型查询引擎。无论是开箱即用的动态 Schema,还是面向编译优化的 SPAC 静态 Schema,其 API 风格始终如一:同步的 DDL、Promise 化的 DML、收敛于lf命名空间、零全局副作用。以此为导读,你可以顺着规范目录逐章深入,也可以在仓库源码中验证文档所述的每一项设计决策。

  • 关系型数据库
  • 数据库
  • 前端

【免费下载链接】lovefield

Lovefield is a relational database for web apps. Written in JavaScript, works cross-browser. Provides SQL-like APIs that are fast, safe, and easy to use.

项目地址:https://gitcode.com/gh_mirrors/lov/lovefield
点击查看免费下载

相关推荐

上一篇:开源项目 `copy` 常见问题解决方案
下一篇:rvCSI 边缘射频感知运行时:RuView 将 WiFi CSI 工程化为可信传感基础设施的架构决策与实践

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询