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

zenorm

v4.5.1

Published

Easy ORM, easy query. easy typing! Auto generate typescript declaration.

Readme

ZenORM

Node.js 数据库 ORM 框架

ZenWeb 衍生的核心项目,此项目可以独立使用

本框架不主动创建数据库结构,而是根据已有数据库结构来生成操作代码,这么做的原因:

  • 在数据库设计层面直接定义表结构比框架生成的通用结构更细致
  • 对于已有项目想要使用 ORM 支持更加友好

本框架并不是真正的 ORM 系统,而是类 ORM 的数据库操作层,几乎任何复杂查询都可实现(试试强大的 AB 工具类)

本框架诞生之因就是为了解决 SAAS 系统的单实例多租户问题,所以所有设计上都是从如何在一个系统中使用多个数据库服务器以及多个数据库而导向, 当然也支持传统的单体应用方式(配置 @zenorm/generatebindQuery 即可)。 以下样例代码即是单体应用的使用方式

安装

# 生产依赖
npm install zenorm mysql-easy-query

# 开发依赖
npm install @zenorm/generate @zenorm/generate-mysql --save-dev

配置

package.jsonscripts 中增加如下代码,用于执行 dbgen 命令

{
  "scripts": {
    "dbgen": "zenorm-generate .dbgen.js"
  }
}

创建文件 .dbgen.js 用于生成数据库结构代码时连接到指定数据库

提示:运行时并不使用此配置

/** @type {import("@zenorm/generate").GenerateConfig} */
export default {
  host: "localhost",
  port: 3306,
  user: "root",
  password: "",
  bindQuery: "pool@../db",
  database: "test"
};

演示

以下数据库结构为演示用,在数据中创建表结构

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `profile` (
  `id` int(11) NOT NULL,
  `edu` varchar(255) DEFAULT NULL,
  `work` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `message` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `content` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

运行命令开始生成数据库结构代码

npm run dbgen

编辑模型关系

编辑生成的模型文件 src/model/user.ts

import { Model, Join, Many } from 'zenorm';
import { UserTable } from './_tables.js';
import { type Profile } from './profile.js';
import * as ProfileRef from './profile.js'; // 互相依赖引入方式
import { Message } from './message.js';

@Model({
  pk: 'id',
  table: 'user',
})
export default class User extends UserTable {
  @Join(ProfileRef, { type: 'OneToMany', asList: false })
  profile?: Profile;

  @Join(Message)
  messages?: Message[];

  @Many(Message)
  messageList?: Message[];

  set age(v) {
    if (v === undefined) throw new Error('age is undefined');
    if (v === 99) return false;
    const date = new Date();
    date.setFullYear(date.getFullYear() - v, 1, 1);
    this.birthday = date;
  }

  get age() {
    return this.birthday ? ((new Date().getFullYear()) - this.birthday.getFullYear()) : undefined;
  }
}

编辑生成的模型文件 src/model/profile.ts

import { Model, Join } from 'zenorm';
import { ProfileTable } from './_tables';
import User from './user';

@Model({
  pk: 'id',
  table: 'profile',
})
export default class Profile extends ProfileTable {
  @Join(User)
  user?: User;
}

初始化数据库访问层

创建代码 src/db.ts

import { createPoolCompatible } from 'mysql-easy-query';
import { Repositories } from './model';

// 创建数据库连接池
export const pool = createPoolCompatible({
  pools: {
    // 主库
    MASTER: {
      host: '10.0.0.1',
      user: 'root',
      database: 'test',
      password: '',
    },
    // 如果需要读写分离,创建命令规则为 SLAVE* 的只读配置
    /*
    SLAVE1: {
      host: '10.0.0.2'
    },
    */
  }
});

开始使用

常规使用

import { User, Message } from './model';

async function test() {
  // create
  const id = await User.create({ name: 'yf' });
  console.log(id); // 1

  // get and update
  const user = await User.findByPk(id);
  user.name = 'yefei';
  user.age = 20;
  await User.save(user);

  // find all
  const users = await User.find().all();

  // find limit
  const users = await User.find().limit(10).all();

  // find by where
  const users = await User.find({ name: { $like: `%y%` } }).all();

  // get all count
  const count = await User.find().count();

  // page
  const page = await User.find().page();

  // exists
  const exists = await User.find({ name: 'yf' }).exists();

  // update
  const updatedCount = await User.find({ id: 1 }).update({ name: 'yf', age: 11 });

  // delete
  const user = await User.findByPk(1);
  const deletedCount = await user.delete();

  // sql delete
  await User.find({ name: 'aaa' }).delete();

  // join 预定义
  const user = await User.find().join("messages").get();

  // join 模型(未定义的)
  const user = await Message.find().join(User).all();

  // many 独立查询功能
  const userList = await User.find().many("messageList").all();

  // 指定使用主从库
  await User.find().of('MASTER').all();
  await User.find().of('SLAVE*').all();
}

事物支持

import { pool } from './db';
import { User, Message } from './model';

async function test() {
  await pool.transaction(async tx => {
    await User.query(tx).find().update({ some: 'data' });
    await Message.query(tx).find().update({ some: 'data' });
  });
}

更多用法

以上仅为常用操作演示,ZenORM 还支持:

  • Join 链式查询(join('user->messages')
  • Many 并行查询
  • 聚合查询(group + having + AB.count
  • 索引提示(useIndex / forceIndex / ignoreIndex
  • 分页(page)、取单值(value / values
  • getOrCreatecreateAndGet
  • Finder clone() 复用
  • 非自增主键模型
  • 手动定义模型(不依赖代码生成)
  • AB 工具类 SQL 表达式

更多用法请参阅 使用指南AI 编程工具的项目参考手册

关联项目