导出完整指南

用途: Schema 到多种输出格式的完整导出指南
阅读时间: 10分钟

⚠️ 重要提示: 并非所有 schema-dsl 特性都能导出到数据库。请先阅读 导出限制说明 了解哪些特性不支持导出。


📑 目录


概述

schema-dsl 支持将 JSON Schema 导出为多种数据库结构或文档格式,实现“一次定义,多处使用”。

支持的导出格式

类型导出器输出格式
MongoDBMongoDBExporter$jsonSchema 验证文档
MySQLMySQLExporterCREATE TABLE DDL
PostgreSQLPostgreSQLExporterCREATE TABLE DDL + COMMENT
MarkdownMarkdownExporter面向人类阅读的 Markdown 文档

其中 MarkdownExporter 更适合生成接口字段说明、表单文档或内部规范文档,完整用法见 Markdown 导出器


快速开始

const { dsl, exporters } = require('schema-dsl');

// 定义统一的 Schema
const userSchema = dsl({
  id: 'uuid!',
  username: 'string:3-32!'
    .pattern(/^[a-zA-Z0-9_]+$/)
    .description('用户登录名'),
  email: 'email!'
    .description('用户邮箱'),
  age: 'number:18-120',
  status: 'active|inactive|banned',
  createdAt: 'datetime!'
});

// 导出到不同目标
const mongoSchema = new exporters.MongoDBExporter().export(userSchema);
const mysqlDdl = new exporters.MySQLExporter().export('users', userSchema);
const pgDdl = new exporters.PostgreSQLExporter().export('users', userSchema);
const markdownDoc = exporters.MarkdownExporter.export(userSchema, {
  title: '用户 Schema 文档'
});

Markdown 导出

如果你的目标不是数据库,而是给研发、测试、产品或接口使用方生成一份可直接阅读的字段说明文档,可以使用 MarkdownExporter

const { dsl, exporters } = require('schema-dsl');

const schema = dsl({
  username: 'string:3-32!'.description('登录账号'),
  email: 'email!'.description('联系邮箱'),
  age: 'number:18-120'.description('年龄')
});

const markdown = exporters.MarkdownExporter.export(schema, {
  title: '用户注册字段说明',
  locale: 'zh-CN'
});

console.log(markdown);

更完整的选项、示例和多语言输出说明见 Markdown 导出器


MongoDB 导出

基本用法

const { dsl, exporters } = require('schema-dsl');

const schema = dsl({
  username: 'string:3-32!',
  email: 'email!',
  age: 'number:18-120'
});

const exporter = new exporters.MongoDBExporter();
const mongoSchema = exporter.export(schema);

console.log(JSON.stringify(mongoSchema, null, 2));

输出

{
  "$jsonSchema": {
    "bsonType": "object",
    "required": ["username", "email"],
    "properties": {
      "username": {
        "bsonType": "string",
        "minLength": 3,
        "maxLength": 32
      },
      "email": {
        "bsonType": "string"
      },
      "age": {
        "bsonType": "double",
        "minimum": 18,
        "maximum": 120
      }
    }
  }
}

生成创建命令

const command = exporter.generateCommand('users', schema);
console.log(command);

输出

db.createCollection("users", {
  "validator": {
    "$jsonSchema": { ... }
  },
  "validationLevel": "moderate",
  "validationAction": "error"
})

在 MongoDB 中使用

const { MongoClient } = require('mongodb');

async function setupCollection() {
  const client = new MongoClient('mongodb://localhost:27017');
  await client.connect();

  const db = client.db('myapp');
  const exporter = new exporters.MongoDBExporter({ strict: true });
  const { options } = exporter.generateCreateCommand('users', schema);

  await db.createCollection('users', options);
  console.log('创建带验证的集合成功');
}

MySQL 导出

基本用法

const { dsl, exporters } = require('schema-dsl');

const schema = dsl({
  id: 'string!',
  username: 'string:3-32!',
  email: 'email!',
  age: 'number:0-150',
  status: 'active|inactive'
});

const exporter = new exporters.MySQLExporter();
const ddl = exporter.export('users', schema);

console.log(ddl);

输出

CREATE TABLE `users` (
  `id` VARCHAR(255) NOT NULL,
  `username` VARCHAR(32) NOT NULL,
  `email` VARCHAR(255) NOT NULL,
  `age` DOUBLE NULL,
  `status` VARCHAR(255) NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

配置选项

const exporter = new exporters.MySQLExporter({
  engine: 'InnoDB',           // 存储引擎
  charset: 'utf8mb4',         // 字符集
  collate: 'utf8mb4_unicode_ci'  // 排序规则
});

生成索引

// 唯一索引
console.log(exporter.generateIndex('users', 'email', { unique: true }));
// CREATE UNIQUE INDEX `idx_users_email` ON `users` (`email`);

// 普通索引
console.log(exporter.generateIndex('users', 'status'));
// CREATE INDEX `idx_users_status` ON `users` (`status`);

PostgreSQL 导出

基本用法

const { dsl, exporters } = require('schema-dsl');

const schema = dsl({
  id: 'uuid!',
  username: 'string:3-32!'
    .description('用户登录名'),
  email: 'email!'
    .description('用户邮箱'),
  age: 'number:18-120',
  status: 'active|inactive|banned',
  metadata: {
    lastLogin: 'datetime',
    preferences: 'object'
  }
});

const exporter = new exporters.PostgreSQLExporter();
const ddl = exporter.export('users', schema);

console.log(ddl);

输出

CREATE TABLE public.users (
  id UUID NOT NULL,
  username VARCHAR(32) NOT NULL CHECK (LENGTH(username) BETWEEN 3 AND 32),
  email VARCHAR(255) NOT NULL,
  age DOUBLE PRECISION CHECK (age BETWEEN 18 AND 120),
  status VARCHAR(255) CHECK (status IN ('active', 'inactive', 'banned')),
  metadata JSONB,
  PRIMARY KEY (id)
);

COMMENT ON COLUMN public.users.username IS '用户登录名';
COMMENT ON COLUMN public.users.email IS '用户邮箱';

配置选项

const exporter = new exporters.PostgreSQLExporter({
  schema: 'myapp'  // PostgreSQL schema 名称
});

生成索引

// B-tree 索引(默认)
console.log(exporter.generateIndex('users', 'email', { unique: true }));
// CREATE UNIQUE INDEX idx_users_email ON public.users USING btree (email);

// GIN 索引(用于 JSONB)
console.log(exporter.generateIndex('users', 'metadata', { method: 'gin' }));
// CREATE INDEX idx_users_metadata ON public.users USING gin (metadata);

导出对比

同一 Schema 的三种导出

const schema = dsl({
  id: 'uuid!',
  name: 'string:3-100!',
  score: 'number:0-100',
  tags: 'array<string>',
  active: 'boolean'
});
字段MongoDBMySQLPostgreSQL
idbsonType: 'string'VARCHAR(255) NOT NULLUUID NOT NULL
namebsonType: 'string', minLength: 3, maxLength: 100VARCHAR(100) NOT NULLVARCHAR(100) NOT NULL CHECK (...)
scorebsonType: 'double', minimum: 0, maximum: 100DOUBLE NULLDOUBLE PRECISION CHECK (...)
tagsbsonType: 'array', items: {...}JSON NULLJSONB
activebsonType: 'bool'BOOLEAN NULLBOOLEAN

约束支持对比

约束类型MongoDBMySQLPostgreSQL
NOT NULLrequiredNOT NULLNOT NULL
长度范围minLength/maxLengthCHECK
数值范围minimum/maximumCHECK
枚举enumCHECK
正则pattern
默认值DEFAULTDEFAULT
注释COMMENTCOMMENT ON

最佳实践

1. 使用 description 添加注释

const schema = dsl({
  username: 'string:3-32!'
    .description('用户登录名,只能包含字母数字下划线'),
  email: 'email!'
    .description('用户邮箱,用于登录和接收通知')
});

// MySQL 和 PostgreSQL 会生成带注释的 DDL

2. 统一定义,多处导出

// schemas/user.js
const { dsl } = require('schema-dsl');

module.exports = dsl({
  id: 'uuid!',
  username: 'string:3-32!',
  email: 'email!',
  createdAt: 'datetime!'
});

// 导出脚本
const { exporters } = require('schema-dsl');
const userSchema = require('./schemas/user');

// 生成所有数据库的 DDL
const outputs = {
  mongo: new exporters.MongoDBExporter().generateCommand('users', userSchema),
  mysql: new exporters.MySQLExporter().export('users', userSchema),
  postgres: new exporters.PostgreSQLExporter().export('users', userSchema)
};

3. 自动化迁移脚本

const fs = require('fs');
const { dsl, exporters } = require('schema-dsl');

function generateMigration(schemaName, schema) {
  const mysql = new exporters.MySQLExporter();
  const pg = new exporters.PostgreSQLExporter();

  const timestamp = Date.now();

  // 生成 MySQL 迁移
  fs.writeFileSync(
    `migrations/${timestamp}_create_${schemaName}.mysql.sql`,
    mysql.export(schemaName, schema)
  );

  // 生成 PostgreSQL 迁移
  fs.writeFileSync(
    `migrations/${timestamp}_create_${schemaName}.pg.sql`,
    pg.export(schemaName, schema)
  );

  console.log(`生成迁移文件: ${schemaName}`);
}

generateMigration('users', userSchema);
generateMigration('orders', orderSchema);

4. 版本管理

// 在 Schema 中添加版本信息
const userSchemaV1 = dsl({ username: 'string!' });
const userSchemaV2 = dsl({ username: 'string:3-32!', email: 'email!' });

// 导出时标注版本
function exportWithVersion(name, schema, version) {
  const ddl = new exporters.MySQLExporter().export(name, schema);
  return `-- Schema Version: ${version}\n-- Generated: ${new Date().toISOString()}\n\n${ddl}`;
}

完整示例

电商系统 Schema 导出

const { dsl, exporters } = require('schema-dsl');
const fs = require('fs');

// 用户 Schema
const userSchema = dsl({
  id: 'uuid!',
  username: 'string:3-32!'.description('用户名'),
  email: 'email!'.description('邮箱'),
  phone: 'string:11'.phone('cn').description('手机号'),
  status: 'active|inactive|banned',
  createdAt: 'datetime!'
});

// 商品 Schema
const productSchema = dsl({
  id: 'uuid!',
  name: 'string:3-200!'.description('商品名称'),
  price: 'number:0-'.description('价格'),
  stock: 'integer:0-'.description('库存'),
  category: 'string:2-50!',
  tags: 'array<string>',
  active: 'boolean'
});

// 订单 Schema
const orderSchema = dsl({
  id: 'uuid!',
  userId: 'uuid!',
  items: 'array!1-100',
  totalAmount: 'number:0-!',
  status: 'pending|paid|shipped|delivered|cancelled',
  createdAt: 'datetime!',
  updatedAt: 'datetime'
});

// 导出所有 Schema
const schemas = { users: userSchema, products: productSchema, orders: orderSchema };
const mysqlExporter = new exporters.MySQLExporter();
const pgExporter = new exporters.PostgreSQLExporter({ schema: 'ecommerce' });

let mysqlDdl = '';
let pgDdl = '';

for (const [name, schema] of Object.entries(schemas)) {
  mysqlDdl += mysqlExporter.export(name, schema) + '\n\n';
  pgDdl += pgExporter.export(name, schema) + '\n\n';
}

fs.writeFileSync('schema.mysql.sql', mysqlDdl);
fs.writeFileSync('schema.pg.sql', pgDdl);

console.log('导出完成!');

相关文档


对应示例文件

示例入口: export-guide.ts
说明: 覆盖同一组 schema 同时导出到 MongoDB、MySQL 和 PostgreSQL 的最小工作流,便于对照多导出器结果。