npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@objectql/driver-fs

v4.2.2

Published

File system driver for ObjectQL - JSON file-based storage with one file per table

Readme

@objectql/driver-fs

ObjectQL 文件系统驱动 - 基于 JSON 文件的持久化存储,每个表一个文件。

特性

持久化存储 - 数据在进程重启后保留
每表一文件 - 每个对象类型存储在独立的 JSON 文件中(例如:users.jsonprojects.json
人类可读 - 格式化的 JSON,便于检查和调试
原子写入 - 临时文件 + 重命名策略防止数据损坏
备份支持 - 写入时自动创建备份文件(.bak
完整查询支持 - 过滤、排序、分页、字段投影
零数据库配置 - 无需外部依赖或数据库安装

安装

npm install @objectql/driver-fs

快速开始

import { ObjectQL } from '@objectql/core';
import { FileSystemDriver } from '@objectql/driver-fs';

// 1. 初始化驱动
const driver = new FileSystemDriver({
    dataDir: './data' // JSON 文件存储目录
});

// 2. 初始化 ObjectQL
const app = new ObjectQL({
    datasources: {
        default: driver
    }
});

// 3. 定义对象
app.registerObject({
    name: 'users',
    fields: {
        name: { type: 'text', required: true },
        email: { type: 'email' },
        age: { type: 'number' }
    }
});

await app.init();

// 4. 使用 API
const ctx = app.createContext({ isSystem: true });
const users = ctx.object('users');

// 创建
await users.create({ name: 'Alice', email: '[email protected]', age: 30 });

// 查询
const allUsers = await users.find({});
console.log(allUsers);

// 带过滤条件查询
const youngUsers = await users.find({
    filters: [['age', '<', 25]]
});

配置选项

interface FileSystemDriverConfig {
    /** JSON 文件存储目录路径 */
    dataDir: string;
    
    /** 启用格式化 JSON 以提高可读性(默认:true) */
    prettyPrint?: boolean;
    
    /** 启用写入时备份文件(默认:true) */
    enableBackup?: boolean;
    
    /** 启用严格模式(缺失对象时抛出错误)(默认:false) */
    strictMode?: boolean;
    
    /** 初始数据(可选) */
    initialData?: Record<string, any[]>;
}

配置示例

const driver = new FileSystemDriver({
    dataDir: './data',
    prettyPrint: true,      // 人类可读的 JSON
    enableBackup: true,     // 创建 .bak 备份文件
    strictMode: false,      // 优雅处理缺失记录
    initialData: {          // 预加载初始数据
        users: [
            { id: 'admin', name: '管理员', role: 'admin' }
        ]
    }
});

文件存储格式

每个对象类型存储在独立的 JSON 文件中:

./data/
  ├── users.json
  ├── users.json.bak      (备份)
  ├── projects.json
  ├── projects.json.bak
  └── tasks.json

文件内容示例(users.json

[
  {
    "id": "users-1234567890-1",
    "name": "Alice",
    "email": "[email protected]",
    "age": 30,
    "created_at": "2024-01-15T10:30:00.000Z",
    "updated_at": "2024-01-15T10:30:00.000Z"
  },
  {
    "id": "users-1234567891-2",
    "name": "Bob",
    "email": "[email protected]",
    "age": 25,
    "created_at": "2024-01-15T11:00:00.000Z",
    "updated_at": "2024-01-15T11:00:00.000Z"
  }
]

API 示例

CRUD 操作

const ctx = app.createContext({ isSystem: true });
const products = ctx.object('products');

// 创建
const product = await products.create({
    name: '笔记本电脑',
    price: 1000,
    category: '电子产品'
});

// 查询单个
const found = await products.findOne(product.id);

// 更新
await products.update(product.id, { price: 950 });

// 删除
await products.delete(product.id);

查询操作

// 过滤
const electronics = await products.find({
    filters: [['category', '=', '电子产品']]
});

// 多条件 OR 查询
const results = await products.find({
    filters: [
        ['price', '<', 500],
        'or',
        ['category', '=', '促销']
    ]
});

// 排序
const sorted = await products.find({
    sort: [['price', 'desc']]
});

// 分页
const page1 = await products.find({
    limit: 10,
    skip: 0
});

// 字段投影
const names = await products.find({
    fields: ['name', 'price']
});

批量操作

// 批量创建
await products.createMany([
    { name: '商品 1', price: 10 },
    { name: '商品 2', price: 20 },
    { name: '商品 3', price: 30 }
]);

// 批量更新
await products.updateMany(
    [['category', '=', '电子产品']], // 过滤条件
    { onSale: true }                  // 更新数据
);

// 批量删除
await products.deleteMany([
    ['price', '<', 10]
]);

// 计数
const count = await products.count({
    filters: [['category', '=', '电子产品']]
});

// 去重值
const categories = await products.distinct('category');

支持的查询操作符

  • 相等性===!=<>
  • 比较>>=<<=
  • 成员innin(不在其中)
  • 字符串匹配likecontainsstartswithendswith
  • 范围between

使用场景

✅ 适用于

  • 小到中等数据集(每个对象 < 10k 条记录)
  • 开发和原型设计,需要持久化数据
  • 配置存储(设置、元数据)
  • 嵌入式应用(Electron、Tauri)
  • 无需数据库的场景(无需数据库配置)
  • 人类可读数据(易于调试和修改)

❌ 不推荐用于

  • 大型数据集(每个对象 > 10k 条记录)
  • 高并发写入(多进程同时写入)
  • 生产环境高流量应用(使用 SQL/MongoDB 驱动替代)
  • 复杂事务(使用支持事务的 SQL 驱动)

性能特征

  • 读性能:过滤查询 O(n),简单查找速度快
  • 写性能:O(n) - 每次更新重写整个文件
  • 存储格式:人类可读的 JSON(比二进制格式大)
  • 并发:单进程安全,多进程需要外部锁

数据安全

原子写入

驱动使用临时文件 + 重命名策略防止损坏:

  1. 将新数据写入 {file}.tmp
  2. 重命名 {file}.tmp{file}(原子操作)
  3. 如果进程在写入过程中崩溃,原始文件保持完整

备份文件

enableBackup: true 时,驱动创建 .bak 文件:

users.json      ← 当前数据
users.json.bak  ← 上一版本

从备份恢复:

cp data/users.json.bak data/users.json

高级用法

自定义 ID 生成

// 使用自己的 ID
await products.create({
    id: 'PROD-001',
    name: '自定义产品'
});

// 或使用 _id(MongoDB 风格)
await products.create({
    _id: '507f1f77bcf86cd799439011',
    name: 'Mongo 风格产品'
});

加载初始数据

方法 1:在配置中提供

const driver = new FileSystemDriver({
    dataDir: './data',
    initialData: {
        users: [
            { id: 'admin-001', name: '管理员', role: 'admin' }
        ],
        settings: [
            { key: 'theme', value: 'dark' }
        ]
    }
});

方法 2:预创建 JSON 文件

// ./data/users.json
[
  {
    "id": "admin-001",
    "name": "管理员",
    "email": "[email protected]",
    "role": "admin",
    "created_at": "2024-01-01T00:00:00.000Z",
    "updated_at": "2024-01-01T00:00:00.000Z"
  }
]

驱动将在启动时加载此数据。

多个数据目录

// 开发环境
const devDriver = new FileSystemDriver({
    dataDir: './data/dev'
});

// 测试环境
const testDriver = new FileSystemDriver({
    dataDir: './data/test'
});

工具方法

// 清除特定对象的所有数据
await driver.clear('users');

// 清除所有对象的数据
await driver.clearAll();

// 使缓存失效
driver.invalidateCache('users');

// 获取缓存大小
const size = driver.getCacheSize();

与其他驱动的对比

| 特性 | FileSystem | Memory | SQL | MongoDB | |------|-----------|--------|-----|---------| | 持久化 | ✅ 是 | ❌ 否 | ✅ 是 | ✅ 是 | | 需要配置 | ❌ 否 | ❌ 否 | ✅ 是 | ✅ 是 | | 人类可读 | ✅ 是 | ❌ 否 | ❌ 否 | ⚠️ 部分 | | 性能(大数据) | ⚠️ 慢 | ✅ 快 | ✅ 快 | ✅ 快 | | 事务 | ❌ 否 | ❌ 否 | ✅ 是 | ✅ 是 | | 最适合 | 开发/配置 | 测试 | 生产 | 生产 |

故障排除

文件损坏

如果 JSON 文件损坏,从备份恢复:

cp data/users.json.bak data/users.json

权限问题

确保进程具有读/写权限:

chmod 755 ./data

文件过大

如果文件变得太大(> 1MB),考虑:

  1. 将数据拆分为多个对象类型
  2. 在生产环境使用 SQL/MongoDB 驱动
  3. 实施数据归档策略

许可证

MIT

贡献

欢迎贡献!请在 GitHub 上开启 issue 或 PR。

相关包