Better-sqlite3 贡献
简介和范围
better-sqlite3
是一个低级别的Node.js包,提供对SQLite的绑定。better-sqlite3
不是一个ORM,也不适用于特定的应用程序或框架。
对于better-sqlite3
来说,SQLite没有直接提供的任何东西都被认为是超出范围的。而SQLite直接提供的东西,如果满足以下额外要求,则可能被认为在better-sqlite3
的范围内:
- 能够合理且安全地实现(即不会导致未定义行为)
- 使用频率足够高,值得为其带来的额外代码复杂性
- 不能由用户在JavaScript中合理实现(例如,通过猴子补丁)
Native addons
better-sqlite3
是JavaScript和C++的组合。C++部分是与底层的SQLite库进行通信所必需的,该库是用C编写的。Node.js通过名为node-gyp
的构建系统支持C++插件,这是每个npm安装时自动捆绑的。在大多数系统上,当运行npm install
时,C++插件将作为安装过程的一部分进行编译。然而,历史已经表明,Windows用户在为Node.js构建C++插件时遇到了很大的困难。这是一个涉及Node.js整体的问题,而不是特定于better-sqlite3
的问题。
Electron
better-sqlite3
是一个Node.js包,而不是一个Electron包。Electron被视为一个第三方平台,官方不支持。然而,许多用户在使用better-sqlite3
与Electron一起使用时取得了巨大的成功,并且像@mceachen这样的有帮助的贡献者为Electron社区提供了支持。
TypeScript
最后,better-sqlite3
是一个JavaScript包,而不是TypeScript包。社区已经在@types/better-sqlite3
中慷慨地提供了类型定义,但目前还没有官方支持TypeScript(这可能会在未来改变)。
原则
贡献给better-sqlite3
的代码必须遵守以下原则(按优先级从高到低排序):
1)正确性
代码在所有情况下都必须表现正常。通常在编写新功能时,只考虑了名义情况。然而,当你考虑到竞争条件、不常见的状态和不正确的使用方式时,就会存在许多边缘情况。必须检测所有不正确的使用方式,并抛出适当的错误(永远不要忽略)。必须支持所有正确的使用方式,并按照预期表现。
2)简单性
better-sqlite3
的公共API必须尽可能简单。与其按特定顺序调用3个函数,不如让用户调用单个函数更简单。与其提供许多类似的函数来执行类似的事情(例如,“便利函数”),不如只有一个已经设计得方便的函数。在可能的情况下应应用合理的默认值。函数的最小调用签名应尽可能小,并在需要时逐步提供复杂的自定义选项。函数名称的长度只需传达其目的即可。对于任何新功能,应该可以轻松展示简单到足以自我解释的代码示例。
这一原则仅适用于公共API,不一定适用于内部函数。
3)可读性
代码必须以一种直观且易于其他程序员理解的方式编写,无论是现在还是将来。有些代码自然复杂,因此应该用注释解释(只在必要时)。代码应以与现有代码相似的方式编写。
如何贡献
如果你从未为Node.js编写过原生插件,你应该首先阅读关于该主题的官方文档。
C++
better-sqlite3
中的C++代码使用名为lzz
的工具编写,这减轻了程序员编写头文件的需求。如果你计划更改任何C++代码,你需要编辑*.lzz
文件,然后通过运行npm run lzz
(当lzz
可执行文件在你的PATH中时)将其重新编译为*.cpp
和*.hpp
。你可以在这里了解如何下载和安装lzz
。
风格指南
目前,better-sqlite3
没有与linter或风格指南关联(这可能会在未来发生变化)。现在,尽量尝试匹配现有代码的风格。如果代码所有者认为你使用了与现有代码不匹配的编码风格,他们可能会拒绝你的PR或重写你的更改。尽管规则没有正式列出,但你应该通过使用你的肉眼来遵守它们。
测试
所有测试都是用JavaScript编写的,它们测试better-sqlite3
的公共API。所有新功能都必须伴随着一套健壮的测试集,这些测试集仔细审查新功能在各种情况下和边缘情况下的表现。仅仅测试“常见情况”是不够的。如果你编写的代码检测到错误并抛出异常,那么这些错误情况也应该被测试,以确保所有错误都被正确检测到。如果新功能与现有功能交互,那么这些交互也必须被测试。
文档
所有新功能都必须伴随清晰的文档。所有新方法和类都必须包含在目录中,并必须包含代码示例。文档必须遵循现有的格式:
- 字面值使用等宽代码格式
- 示例:
"my string"
,true
,false
,null
,undefined
,123
- 示例:
- 包名和代码标识符使用等宽代码格式
- 示例:
better-sqlite3
,db.myMethod()
,options.readOnly
,this
- 示例:
- 基本数据类型为小写,其他数据类型为大写
- 示例:
string
,number
,Buffer
,Database
- 示例:
- 对其他类或方法的引用必须链接并使用等宽代码格式
- 示例:
.get()
,new Database()
- 示例:
- 函数签名写成:.funcName(requiredArg, [optionalArg]) -> returnValue
- 注意参数和返回值是斜体的
- 注意可选参数用方括号[]包围
- 所有代码块都应使用
js
语法高亮显示,除了不需要高亮的bash命令
贡献类别
根据你贡献的性质,它将受到不同程度的审查,从最低到最高:
1) 一般维护
这些更改是不言自明的。它们包括:
- 更新捆绑的SQLite版本(使用此工作流程)
- 更新
package.json
中的依赖项 - 添加新版本的Node.js或Electron的预构建二进制文件
- 添加新架构或操作系统的预构建二进制文件
这类更新定期进行,无需了解better-sqlite3
的代码。受信任的贡献者可以在没有原作者批准的情况下合并这些更改。
2) 文档
对文档的更改通常是有益的且无害的。然而,由于它们影响了用户了解和使用better-sqlite3
的方式,因此应对其进行更高程度的审查。重视文档的正确性和真实性。例如,文档不应基于我们无法控制的事件而“过时”。
根据文档的类型,受信任的贡献者可能能够在没有原作者批准的情况下合并这些更改。
3) 微小的质量改进
这些是代码更改,影响范围很小,例如向对象添加只读属性,或者为直接传递给SQLite的新选项扩展函数。这些更改可能是无害的,但需要额外的审查,因为它们必须经过彻底的测试和记录。除非它们是主要版本更新的一部分,否则这些更改必须是完全向后兼容的。
删除预构建二进制文件被认为是向后不兼容的变化。
4) 新功能
这些是代码更改,影响范围很大,例如实现新的类或方法。除非它们是主要版本更新的一部分,否则这些更改必须是完全向后兼容的。
外部贡献者很少被接受提供新功能,因为他们很少能达到better-sqlite3
为自己设定的极高标准。新功能必须在所有可能的情况下正确运行,包括竞争条件和边缘情况。同样,即使是最罕见的情况下也必须有测试用例覆盖它们。
在实现新功能时,请问自己:
- 如果我在执行用户定义的函数时使用此功能会发生什么?
- 如果我在遍历预处理语句时使用此功能会发生什么?
- 如果数据库关闭时使用此功能会发生什么?
- 如果我在详细回调中使用此功能会发生什么?
- 如果我在事务中使用此功能会发生什么?
- 如果我在具有绑定参数的预处理语句中使用此功能会发生什么?
- 如果我在工作线程中使用此功能会发生什么?
- 如果传递了错误的数据类型会发生什么?
- 如果传递了意外的值,如
null
、undefined
、""
、NaN
、负数/非整数等会发生什么? - 用户的64位整数设置是否会影响此功能?
- 如果此功能接受回调函数:
- 如果回调函数抛出异常会发生什么?
- 如果在这些情况下触发回调函数会发生什么?
- 此功能是否会导致内存泄漏?
- 如果一个C++对象在JavaScript中打开句柄时被垃圾回收会发生什么?
- 如果我在分配C++对象后在回调中抛出JavaScript错误会发生什么?
人们喜欢better-sqlite3
是因为它的鲁棒性和可靠性。better-sqlite3
的每一个特性都考虑了上述列出的每一个场景。此外,所有可能的错误场景都被明确处理和测试过。任何新的better-sqlite3
特性都必须达到同样的标准。目前,未经原作者批准,任何新特性都不会被合并。