SkillAgentSearch skills...

Lubejs

Use oracle db as mongodb in node.js, base on node-oracledb

Install / Use

/learn @jovercao/Lubejs
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Lubejs

Lubejs 是一个用于 node.js 诣在方便使用SQL数据库连接. 取名为lube意为润滑,即作为js与sql间的润滑剂般的存在,我们可以尽情使用优雅的 js/ts来 替代拼接 sql 字符串。

本库部分灵感来自于EFTypeORM,致谢

English

lubejs是什么

lubejs 是一套类型化sql构建、执行工具,亦是一套强大易用的Typescript ORM开发框架。

  • 完备的SQL构建工具,使用最贴近SQL的语法编写SQL,极低的学习成本
  • 强大的Typescript类型支持,支持反向类型推导,返回明确类型,拥有完整类型安全体系,智能语法提示,提高开发效率以及预排除类型错误,强烈建立在typescript项目中使用lubejs。
  • ORM配套工具,Code first、数据迁移
  • 匹配多种数据库(目前只支持mssql)
  • 跨数据库兼容,为此,lubejs建立了标准行为库,把大多数常用的,而在各个数据库中又不尽相同的操作行为,包括在其中。

lubejs理念

  • 简洁,极简api,极易上手
  • 贴近自然,语法与标准sql极为接近,大大降低学习成本
  • 渐进式,lubejs分为两个层级的引用,core及完整功能包
  • 多数据库方言统一兼容,建立中间标准操作库并不断丰富。
  • 完整的typescript类型安全

快速开始

安装

使用 npm 安装:

# 安装lubejs库
npm install lubejs --save

# 安装lubejs-mssql驱动
npm install lubejs-mssql

开始

Hello world!

// hello-world.ts
import { connect, SQL } from 'lubejs'
// 导入mssql驱动
import 'lubejs-mssql'

(async () => {
  // 创建连接
  const db = await connect('mssql://user:password@localhost:1433/database');
  // SELECT 'hello world'
  console.log(await db.queryScalar(SQL.select('hello world!')));  // => 'hello world'

  await db.close();
})()

完整范例

// example.ts
import {
  connect,
  SQL,
  Decimal,
  Uuid,
  Connection,
  DbType,
  outputCommand,
} from "lubejs";
import "lubejs-mssql";

interface Table1 {
  id: number;
  name: string;
  stringField?: string;
  floatField?: number;
  dateField?: Date;
  decimalField?: Decimal;
  uuidField?: Uuid;
  updatedAt: Date;
  binaryField?: ArrayBuffer;
  createdAt: Date;
  operator?: string;
}

interface Pay {
  id?: number;
  year: number;
  month: number;
  amount: Decimal;
  personId: number;
}

interface Person {
  id?: number;
  name: string;
  age: number;
}

/**
 * 初始化数据库
 */
async function initDb(db: Connection) {
  await db.query(
    SQL.if(SQL.std.existsTable('table1')).then(SQL.dropTable("table1"))
  );

  await db.query(
    SQL.createTable("table1").as(({ column }) => [
      column("id", DbType.int32).identity().primaryKey(),
      column("name", DbType.string(100)).notNull(),
      column("stringField", DbType.string(100)).null(),
      column("floatField", DbType.float).null(),
      column("dateField", DbType.datetimeoffset).null(),
      column("decimalField", DbType.decimal(18, 6)),
      column("uuidField", DbType.uuid),
      column("updatedAt", DbType.datetimeoffset).default(SQL.std.now()),
      column("binaryField", DbType.binary(DbType.MAX)),
      column("createdAt", DbType.datetimeoffset).default(SQL.std.now()),
      column("operator", DbType.string(100)).null(),
    ])
  );

  await db.query(
    SQL.if(SQL.std.existsTable('pay')).then(SQL.dropTable("pay"))
  );

  await db.query(
    SQL.createTable("pay").as(({ column }) => [
      column("id", DbType.int32).identity().primaryKey(),
      column("year", DbType.int32),
      column("month", DbType.int32),
      column("amount", DbType.decimal(18, 2)),
      column("personId", DbType.int32),
    ])
  );

  await db.query(
    SQL.if(SQL.std.existsTable('person')).then(SQL.dropTable("person"))
  );

  await db.query(
    SQL.createTable("person").as(({ column }) => [
      column("id", DbType.int32).identity().primaryKey(),
      column("name", DbType.int32).notNull(),
      column("age", DbType.int32),
    ])
  );

}

/**
 * Table1表声明
 */
// 这是一个范例
async function example(db: Connection) {
  //---------------插入数据------------------
  /*
   * INSERT INTO table1 (stringField, floatField, dateField)
   * VALUES ('value1-1', 2, Convert(DATETIMEOFFSET, '2019-11-18 00:00:00'))
   * ('value1-2', 1, Convert(DATETIMEOFFSET, '2019-11-18 00:00:00'))
   * ('value1-3', 45, Convert(DATETIMEOFFSET, '2019-11-18 00:00:00'))
   */
  const insertSql = SQL.insert<Table1>("table1").values([
    {
      name: "item1",
      stringField: "value1-1",
      floatField: 3.14,
      dateField: new Date(),
      decimalField: new Decimal("3.1415"),
      uuidField: Uuid.new(),
      binaryField: Buffer.from('abcdefeg')
    },
    {
      name: "item2",
      stringField: "value1-2",
      floatField: 1.132,
      dateField: new Date(),
      decimalField: new Decimal("3.1415"),
      uuidField: Uuid.new(),
      binaryField: Buffer.from('abcdefeg')
    },
    {
      name: "item3",
      stringField: "value1-3",
      floatField: 45.2656,
      dateField: new Date(),
      decimalField: new Decimal("3.1415"),
      uuidField: Uuid.new(),
      binaryField: Buffer.from('abcdefeg')
    },
  ]);

  await db.query(insertSql);

  // 你还以使用以下方式插入,等效于上面的写法
  await db.insert<Table1>("table1", [
    {
      name: "item1",
      stringField: "value1-1",
      floatField: 3.14,
      dateField: new Date(),
      decimalField: new Decimal("3.1415"),
      uuidField: Uuid.new(),
      binaryField: Buffer.from('abcdefeg')
    },
    {
      name: "item2",
      stringField: "value1-2",
      floatField: 1.132,
      dateField: new Date(),
      decimalField: new Decimal("3.1415"),
      uuidField: Uuid.new(),
      binaryField: Buffer.from('abcdefeg')
    },
    {
      name: "item3",
      stringField: "value1-3",
      floatField: 45.2656,
      dateField: new Date(),
      decimalField: new Decimal("3.1415"),
      uuidField: Uuid.new(),
      binaryField: Buffer.from('abcdefeg')
    },
  ]);

  //---------------更新数据------------------
  // UPDATE t SET updatedAt = Convert(DateTime, '2019-11-18 00:00:00') FROM table1 t WHERE id = 1
  const t = SQL.table<Table1>("table1").as("t");
  const updateSql = SQL.update(t)
    .set({ updatedAt: new Date(), operator: "your name" })
    .where(t.id.eq(1));
  await db.query(updateSql);

  // 你还以使用以下方式更新,等效于上面的写法
  await db.update<Table1>(
    "table1",
    { updatedAt: new Date(), operator: "your name" },
    { id: 1 }
  );

  //---------------删除数据-------------------
  // DELETE t FROM table1 t WHERE t.id = 1
  const deleteSql = SQL.delete(t).from(t).where(t.id.eq(1));
  await db.query(deleteSql);

  // 你还以使用以下方式删除
  // DELETE table1 WHERE id = 1
  await db.delete("table1", { id: 1 });

  //----------------查询数据--------------------
  // SELECT t.* FROM table1 AS t WHERE t.id = 1 AND t.name = 'name1'
  const selectSql = SQL.select(t.star)
    .from(t)
    .where(SQL.and(t.id.eq(1), t.name.eq("name1")));
  console.log((await db.query(selectSql)).rows);

  //  You can also select in this way
  // SELECT * FROM table1 WHERE id = 1 AND name = 'name1'
  console.log(
    await await db.select("table1", {
      where: {
        id: 1,
        name: "item1",
      },
    })
  );

  // //---------------以下是一个复合查询------------
  const p = SQL.table<Person>("person").as("p");
  const pay = SQL.table<Pay>("pay");
  const sql = SQL.select({
        year: pay.year,
        month: pay.month,
        name: p.name,
        age: p.age,
        total: SQL.std.sum(pay.amount),
  })
    .from(pay)
    .join(p, pay.personId.eq(p.id))
    .where(p.age.lte(18))
    .groupBy(p.name, p.age, pay.year, pay.month)
    .having(SQL.std.sum(pay.amount).gte(new Decimal(100000)))
    .orderBy(pay.year.asc(), pay.month.asc(), SQL.std.sum(pay.amount).asc(), p.age.asc())
    .offset(20)
    .limit(50);

  console.log((await db.query(sql)).rows);
}


(async () => {
  // 创建一个Lube连接
  const db = await connect("mssql://sa:!crgd-2021@rancher.vm/Test");
  // 打开连接
  await db.open();
  // 输出日志
  db.on('command', (cmd) => outputCommand(cmd, process.stdout))
  try {
    await initDb(db);
    await example(db);
  } finally {
    await db.close();
  }
})();

版本说明

注意: lubejs目前仍为预览版,内部会有部分调整,公共API可能会有小许调整,但不会有大调整。

渐进式分离

  • lubejs/core 为核心包,包括sql构建以及sql执行工具。
  • lubejs则为完整包,包括lubejs/core的所有内容以及orm功能,数据迁移cli等。

数据库支持列表

  • [x] mssql - 目前支持microsoft sqlserver 2012 或更高版本, 库基于 node-mssql开发.
  • [ ] mysql - 当前正在开发中
  • [ ] postgresql - 计划于2021年底开发

NodeJs版本支持

nodejs >= 12.0

概念

SQL构造器(SQL对象)

所有的SQL构造,均由 SQL对象发起,几乎所有的SQL的语句,均可从SQL对象创建,例如SQL.selectSQL.update,SQL.delete等。

// 导入SQL对象
import { SQL } from 'lubejs';

为了更贴近sql语法,您还可以使用解构来引入需要的关键字

const {
    insert,
    delete: $delete // 关键字delete需要使用别名
} = SQL

// 构建插入张三、李四两条记录到table1的语句
const sql = insert('table1').values([{ name: '张三', age: 19, sex: '男' }, { name: '李四', age: 25, sex: '男' }]);

// 构建table1表中删除id为1记录的sql语句
const sql = $delete('table1').where({ id: 1 })

更多SQL对象用法,请翻阅《api参考》

注意:deletejs关键字,需要使用别名代替,其它关键字亦是如此

标准行为(SQL.std)

lubejs为了更大程序的兼容多数据库,专门定义了标准行为,用于统一在跨数据库时的操作,避免在跨方言数据库迁移是的重复劳动。

SQL.std中定义了许多常用的函数、操作等行为

常用函数

| 说明 | 函数 | 备注 | | -------------------- | ------------------------------------------------------------ | ---- | | 类型转换 | SQL.std.convert(expr, dbType)Expression.prototype.to(dbType) | | | 当值为空时返回默认值 | SQL.std.nvl(value, defaultValue) | |

聚合函数

| 说明 | 函数 | 备注 | | ------ | --------------------- | ---- | | 计数 | SQL.std.count(expr) | | | 平均 | SQL.std.avg(expr) | | | 求和 | SQL.std.sum(expr) | | | 最大值 | SQL.std.max(expr) | | | 最小值 | SQL.std.min(expr) | |

日期函数

| 说明 | 函数 | 备注 | | ---------------------- | -------------------------------------- | ---- | | 当前时间 | SQL.std.now(expr) | | | UTC当前时间 | SQL.std.utcNow(expr) | | | 切换时区 | SQL.std.switchTimezone(date, offset) | | | 格式化日期 | SQL.std.formatDate(date, format) | | | 取日期中的年份 | SQL.std.yearOf(date) | | | 取日期中的月份 | SQL.std.monthOf(date) | | | 取日期中的日期 | SQL.std.dayOf(date) | | | 取两个日期之间的天数 | SQL.std.daysBetween(star, end) | | | 取两个日期之间的月数 | SQL.std.monthsBetween(star, end) | | | 取两个日期之间的年数 | `

View on GitHub
GitHub Stars4
CategoryDevelopment
Updated4y ago
Forks1

Languages

TypeScript

Security Score

70/100

Audited on Jan 26, 2022

No findings