Drizzle HTTP 代理

本指南假定您已熟悉:

HTTP 代理如何工作,以及为什么你可能需要它

Drizzle Proxy 用于你需要实现自己与数据库的驱动通信时。 它可以用于多种场景,例如在现有驱动的查询阶段添加自定义逻辑。 最常见的用法是与 HTTP 驱动配合使用,它会将查询发送到你服务器上的数据库,执行查询, 并返回原始数据,之后 Drizzle ORM 可以将这些数据映射为结果

底层是如何工作的?

┌───────────────────────────┐                 ┌─────────────────────────────┐              
│       Drizzle ORM         │                 │  带数据库的 HTTP 服务器        │             
└─┬─────────────────────────┘                 └─────────────────────────┬───┘             
  │                                                ^                    │
  │-- 1. 构建查询         2. 发送构建好的查询 --│                    │
  │                                                │                    │
  │              ┌───────────────────────────┐     │                    │
  └─────────────>│                           │─────┘                    │ 
                 │      HTTP 代理驱动         │                          │
  ┌──────────────│                           │<─────────────┬───────────┘
  │              └───────────────────────────┘              │
  │                                                  3. 执行查询 + 将原始结果返回
  │-- 4. 映射数据并返回        

  v

Drizzle ORM 也支持仅使用异步回调函数来执行 SQL。

Drizzle 始终等待返回值为 {rows: string[][]}{rows: string[]}


// 驱动实现示例
import { drizzle } from 'drizzle-orm/mysql-proxy';
import axios from "axios";

const db = drizzle(async (sql, params, method) => {
  try {
    const rows = await axios.post('http://localhost:3000/query', { sql, params, method });

    return { rows: rows.data };
  } catch (e: any) {
    console.error('来自 mysql 代理服务器的错误:', e.response.data)
    return { rows: [] };
  }
});
// 服务器实现示例
import * as mysql from 'mysql2/promise';
import express from 'express';

const app = express();

app.use(express.json());
const port = 3000;

const main = async () => {
    const connection = await mysql.createConnection('mysql://root:mysql@127.0.0.1:5432/drizzle');

    app.post('/query', async (req, res) => {
      const { sql, params, method } = req.body;

      // 防止多条查询
      const sqlBody = sql.replace(/;/g, '');

      try {
            const result = await connection.query({
                sql: sqlBody,
                values: params,
                rowsAsArray: method === 'all',
                typeCast: function(field: any, next: any) {
                    if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') {
                        return field.string();
                    }
                    return next();
                },
            });
      } catch (e: any) {
        res.status(500).json({ error: e });
      }

      if (method === 'all') {
        res.send(result[0]);
      } else if (method === 'execute') {
        res.send(result);
      }
      res.status(500).json({ error: '未知的方法值' });
    });

    app.listen(port, () => {
      console.log(`示例应用正在端口 ${port} 上监听`);
    });
}

main();