schema-dsl 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/CHANGELOG.md +130 -113
  2. package/LICENSE +21 -21
  3. package/README.md +628 -628
  4. package/dist/{DslBuilder-DkLaOo9Q.d.ts → DslBuilder-BIgQOAXp.d.ts} +2 -0
  5. package/dist/{DslBuilder-DQDN0ZxZ.d.cts → DslBuilder-CjHTucNQ.d.cts} +2 -0
  6. package/dist/{Validator-hFWKGxir.d.ts → Validator-CllRdrY0.d.ts} +1 -1
  7. package/dist/{Validator-C7GsVQOH.d.cts → Validator-D6okG9tr.d.cts} +1 -1
  8. package/dist/index.cjs +75 -29
  9. package/dist/index.d.cts +10 -4
  10. package/dist/index.d.ts +10 -4
  11. package/dist/index.js +75 -29
  12. package/dist/plugins/custom-format.cjs +33 -17
  13. package/dist/plugins/custom-format.d.cts +1 -1
  14. package/dist/plugins/custom-format.d.ts +1 -1
  15. package/dist/plugins/custom-format.js +33 -17
  16. package/dist/plugins/custom-type-example.cjs +33 -17
  17. package/dist/plugins/custom-type-example.d.cts +1 -1
  18. package/dist/plugins/custom-type-example.d.ts +1 -1
  19. package/dist/plugins/custom-type-example.js +33 -17
  20. package/dist/plugins/custom-validator.cjs +0 -2
  21. package/dist/plugins/custom-validator.d.cts +1 -1
  22. package/dist/plugins/custom-validator.d.ts +1 -1
  23. package/dist/plugins/custom-validator.js +0 -2
  24. package/docs/FEATURE-INDEX.md +553 -553
  25. package/docs/add-custom-locale.md +496 -496
  26. package/docs/add-keyword.md +24 -24
  27. package/docs/api-reference.md +1047 -1047
  28. package/docs/api.md +13 -13
  29. package/docs/best-practices-project-structure.md +417 -417
  30. package/docs/best-practices.md +712 -712
  31. package/docs/cache-manager.md +344 -344
  32. package/docs/compile.md +45 -45
  33. package/docs/conditional-api.md +1307 -1307
  34. package/docs/custom-extensions-guide.md +339 -339
  35. package/docs/design-philosophy.md +606 -606
  36. package/docs/doc-index.md +324 -324
  37. package/docs/dsl-syntax.md +714 -714
  38. package/docs/dynamic-locale.md +608 -608
  39. package/docs/enum.md +482 -482
  40. package/docs/error-handling.md +1975 -1975
  41. package/docs/export-guide.md +501 -501
  42. package/docs/export-limitations.md +567 -567
  43. package/docs/faq.md +596 -596
  44. package/docs/frontend-i18n-guide.md +307 -307
  45. package/docs/i18n-user-guide.md +487 -487
  46. package/docs/i18n.md +476 -476
  47. package/docs/index.md +48 -48
  48. package/docs/json-schema-basics.md +40 -40
  49. package/docs/label-vs-description.md +271 -271
  50. package/docs/markdown-exporter.md +406 -406
  51. package/docs/mongodb-exporter.md +302 -302
  52. package/docs/multi-language.md +26 -26
  53. package/docs/multi-type-support.md +322 -322
  54. package/docs/mysql-exporter.md +280 -280
  55. package/docs/number-operators.md +449 -449
  56. package/docs/optional-marker-guide.md +326 -326
  57. package/docs/performance-guide.md +49 -49
  58. package/docs/plugin-system.md +381 -381
  59. package/docs/plugin-type-registration.md +34 -34
  60. package/docs/postgresql-exporter.md +311 -311
  61. package/docs/public/favicon.svg +4 -4
  62. package/docs/quick-start.md +435 -435
  63. package/docs/runtime-locale-support.md +532 -532
  64. package/docs/schema-helper.md +345 -345
  65. package/docs/schema-utils-advanced-issues.md +23 -23
  66. package/docs/schema-utils-best-practices.md +20 -20
  67. package/docs/schema-utils-chaining.md +150 -150
  68. package/docs/schema-utils.md +524 -524
  69. package/docs/security-checklist.md +20 -20
  70. package/docs/string-extensions.md +488 -488
  71. package/docs/troubleshooting.md +486 -486
  72. package/docs/type-converter.md +310 -310
  73. package/docs/type-reference.md +242 -242
  74. package/docs/typescript-guide.md +584 -584
  75. package/docs/union-type-guide.md +157 -157
  76. package/docs/union-types.md +284 -284
  77. package/docs/validate-async.md +491 -491
  78. package/docs/validate-batch.md +49 -49
  79. package/docs/validate-dsl-object-support.md +578 -578
  80. package/docs/validate.md +506 -506
  81. package/docs/validation-guide.md +502 -502
  82. package/docs/validator.md +39 -39
  83. package/package.json +131 -131
  84. package/plugins/custom-format.cjs +8 -8
  85. package/plugins/custom-type-example.cjs +8 -8
  86. package/plugins/custom-validator.cjs +8 -8
  87. package/src/adapters/DslAdapter.ts +111 -111
  88. package/src/adapters/index.ts +1 -1
  89. package/src/config/constants.ts +83 -83
  90. package/src/config/index.ts +2 -2
  91. package/src/config/patterns.ts +77 -77
  92. package/src/core/CacheManager.ts +169 -159
  93. package/src/core/ConditionalBuilder.ts +382 -382
  94. package/src/core/ConditionalRuntime.ts +27 -27
  95. package/src/core/ConditionalValidator.ts +254 -254
  96. package/src/core/DslBuilder.ts +687 -677
  97. package/src/core/ErrorCodes.ts +38 -38
  98. package/src/core/ErrorFormatter.ts +271 -271
  99. package/src/core/JSONSchemaCore.ts +65 -65
  100. package/src/core/Locale.ts +187 -187
  101. package/src/core/MessageTemplate.ts +42 -42
  102. package/src/core/ObjectDslBuilder.ts +64 -64
  103. package/src/core/PluginManager.ts +326 -326
  104. package/src/core/StringExtensions.ts +140 -140
  105. package/src/core/TemplateEngine.ts +44 -44
  106. package/src/core/Validator.ts +448 -448
  107. package/src/errors/I18nError.ts +159 -159
  108. package/src/errors/ValidationError.ts +105 -105
  109. package/src/exporters/BaseExporter.ts +60 -60
  110. package/src/exporters/MarkdownExporter.ts +305 -305
  111. package/src/exporters/MongoDBExporter.ts +126 -126
  112. package/src/exporters/MySQLExporter.ts +156 -155
  113. package/src/exporters/PostgreSQLExporter.ts +222 -222
  114. package/src/exporters/index.ts +18 -18
  115. package/src/index.ts +651 -633
  116. package/src/locales/en-US.ts +160 -160
  117. package/src/locales/es-ES.ts +160 -160
  118. package/src/locales/fr-FR.ts +160 -160
  119. package/src/locales/index.ts +103 -103
  120. package/src/locales/ja-JP.ts +160 -160
  121. package/src/locales/types.ts +156 -156
  122. package/src/locales/zh-CN.ts +160 -160
  123. package/src/parser/ConstraintParser.ts +101 -101
  124. package/src/parser/DslParser.ts +470 -470
  125. package/src/parser/SchemaCompiler.ts +66 -66
  126. package/src/parser/TypeRegistry.ts +250 -250
  127. package/src/parser/index.ts +6 -6
  128. package/src/plugins/custom-format.ts +124 -126
  129. package/src/plugins/custom-type-example.ts +106 -108
  130. package/src/plugins/custom-validator.ts +138 -140
  131. package/src/types/conditional.ts +28 -28
  132. package/src/types/config.ts +59 -59
  133. package/src/types/dsl.ts +131 -131
  134. package/src/types/error.ts +60 -60
  135. package/src/types/index.ts +17 -17
  136. package/src/types/infer.ts +127 -127
  137. package/src/types/plugin.ts +58 -58
  138. package/src/types/safe-regex.d.ts +9 -9
  139. package/src/types/schema.ts +66 -66
  140. package/src/types/validate.ts +71 -71
  141. package/src/utils/SchemaHelper.ts +196 -196
  142. package/src/utils/SchemaUtils.ts +365 -346
  143. package/src/utils/TypeConverter.ts +215 -215
  144. package/src/utils/index.ts +10 -10
  145. package/src/validators/CustomKeywords.ts +477 -477
@@ -1,501 +1,501 @@
1
- # 导出完整指南
2
-
3
- > **用途**: Schema 到多种输出格式的完整导出指南
4
- > **阅读时间**: 10分钟
5
-
6
- > ⚠️ **重要提示**: 并非所有 schema-dsl 特性都能导出到数据库。请先阅读 [导出限制说明](export-limitations.md) 了解哪些特性不支持导出。
7
-
8
- ---
9
-
10
- ## 📑 目录
11
-
12
- - [概述](#概述)
13
- - [快速开始](#快速开始)
14
- - [MongoDB 导出](#mongodb-导出)
15
- - [MySQL 导出](#mysql-导出)
16
- - [PostgreSQL 导出](#postgresql-导出)
17
- - [Markdown 导出](#markdown-导出)
18
- - [导出对比](#导出对比)
19
- - [最佳实践](#最佳实践)
20
-
21
- ---
22
-
23
- ## 概述
24
-
25
- schema-dsl 支持将 JSON Schema 导出为多种数据库结构或文档格式,实现“一次定义,多处使用”。
26
-
27
- ### 支持的导出格式
28
-
29
- | 类型 | 导出器 | 输出格式 |
30
- |------|--------|----------|
31
- | MongoDB | `MongoDBExporter` | `$jsonSchema` 验证文档 |
32
- | MySQL | `MySQLExporter` | `CREATE TABLE` DDL |
33
- | PostgreSQL | `PostgreSQLExporter` | `CREATE TABLE` DDL + COMMENT |
34
- | Markdown | `MarkdownExporter` | 面向人类阅读的 Markdown 文档 |
35
-
36
- 其中 `MarkdownExporter` 更适合生成接口字段说明、表单文档或内部规范文档,完整用法见 [Markdown 导出器](./markdown-exporter.md)。
37
-
38
- ---
39
-
40
- ## 快速开始
41
-
42
- ```javascript
43
- const { dsl, exporters } = require('schema-dsl');
44
-
45
- // 定义统一的 Schema
46
- const userSchema = dsl({
47
- id: 'uuid!',
48
- username: 'string:3-32!'
49
- .pattern(/^[a-zA-Z0-9_]+$/)
50
- .description('用户登录名'),
51
- email: 'email!'
52
- .description('用户邮箱'),
53
- age: 'number:18-120',
54
- status: 'active|inactive|banned',
55
- createdAt: 'datetime!'
56
- });
57
-
58
- // 导出到不同目标
59
- const mongoSchema = new exporters.MongoDBExporter().export(userSchema);
60
- const mysqlDdl = new exporters.MySQLExporter().export('users', userSchema);
61
- const pgDdl = new exporters.PostgreSQLExporter().export('users', userSchema);
62
- const markdownDoc = exporters.MarkdownExporter.export(userSchema, {
63
- title: '用户 Schema 文档'
64
- });
65
- ```
66
-
67
- ---
68
-
69
- ## Markdown 导出
70
-
71
- 如果你的目标不是数据库,而是给研发、测试、产品或接口使用方生成一份可直接阅读的字段说明文档,可以使用 `MarkdownExporter`:
72
-
73
- ```javascript
74
- const { dsl, exporters } = require('schema-dsl');
75
-
76
- const schema = dsl({
77
- username: 'string:3-32!'.description('登录账号'),
78
- email: 'email!'.description('联系邮箱'),
79
- age: 'number:18-120'.description('年龄')
80
- });
81
-
82
- const markdown = exporters.MarkdownExporter.export(schema, {
83
- title: '用户注册字段说明',
84
- locale: 'zh-CN'
85
- });
86
-
87
- console.log(markdown);
88
- ```
89
-
90
- 更完整的选项、示例和多语言输出说明见 [Markdown 导出器](./markdown-exporter.md)。
91
-
92
- ---
93
-
94
- ## MongoDB 导出
95
-
96
- ### 基本用法
97
-
98
- ```javascript
99
- const { dsl, exporters } = require('schema-dsl');
100
-
101
- const schema = dsl({
102
- username: 'string:3-32!',
103
- email: 'email!',
104
- age: 'number:18-120'
105
- });
106
-
107
- const exporter = new exporters.MongoDBExporter();
108
- const mongoSchema = exporter.export(schema);
109
-
110
- console.log(JSON.stringify(mongoSchema, null, 2));
111
- ```
112
-
113
- **输出**:
114
-
115
- ```json
116
- {
117
- "$jsonSchema": {
118
- "bsonType": "object",
119
- "required": ["username", "email"],
120
- "properties": {
121
- "username": {
122
- "bsonType": "string",
123
- "minLength": 3,
124
- "maxLength": 32
125
- },
126
- "email": {
127
- "bsonType": "string"
128
- },
129
- "age": {
130
- "bsonType": "double",
131
- "minimum": 18,
132
- "maximum": 120
133
- }
134
- }
135
- }
136
- }
137
- ```
138
-
139
- ### 生成创建命令
140
-
141
- ```javascript
142
- const command = exporter.generateCommand('users', schema);
143
- console.log(command);
144
- ```
145
-
146
- **输出**:
147
-
148
- ```javascript
149
- db.createCollection("users", {
150
- "validator": {
151
- "$jsonSchema": { ... }
152
- },
153
- "validationLevel": "moderate",
154
- "validationAction": "error"
155
- })
156
- ```
157
-
158
- ### 在 MongoDB 中使用
159
-
160
- ```javascript
161
- const { MongoClient } = require('mongodb');
162
-
163
- async function setupCollection() {
164
- const client = new MongoClient('mongodb://localhost:27017');
165
- await client.connect();
166
-
167
- const db = client.db('myapp');
168
- const exporter = new exporters.MongoDBExporter({ strict: true });
169
- const { options } = exporter.generateCreateCommand('users', schema);
170
-
171
- await db.createCollection('users', options);
172
- console.log('创建带验证的集合成功');
173
- }
174
- ```
175
-
176
- ---
177
-
178
- ## MySQL 导出
179
-
180
- ### 基本用法
181
-
182
- ```javascript
183
- const { dsl, exporters } = require('schema-dsl');
184
-
185
- const schema = dsl({
186
- id: 'string!',
187
- username: 'string:3-32!',
188
- email: 'email!',
189
- age: 'number:0-150',
190
- status: 'active|inactive'
191
- });
192
-
193
- const exporter = new exporters.MySQLExporter();
194
- const ddl = exporter.export('users', schema);
195
-
196
- console.log(ddl);
197
- ```
198
-
199
- **输出**:
200
-
201
- ```sql
202
- CREATE TABLE `users` (
203
- `id` VARCHAR(255) NOT NULL,
204
- `username` VARCHAR(32) NOT NULL,
205
- `email` VARCHAR(255) NOT NULL,
206
- `age` DOUBLE NULL,
207
- `status` VARCHAR(255) NULL,
208
- PRIMARY KEY (`id`)
209
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
210
- ```
211
-
212
- ### 配置选项
213
-
214
- ```javascript
215
- const exporter = new exporters.MySQLExporter({
216
- engine: 'InnoDB', // 存储引擎
217
- charset: 'utf8mb4', // 字符集
218
- collate: 'utf8mb4_unicode_ci' // 排序规则
219
- });
220
- ```
221
-
222
- ### 生成索引
223
-
224
- ```javascript
225
- // 唯一索引
226
- console.log(exporter.generateIndex('users', 'email', { unique: true }));
227
- // CREATE UNIQUE INDEX `idx_users_email` ON `users` (`email`);
228
-
229
- // 普通索引
230
- console.log(exporter.generateIndex('users', 'status'));
231
- // CREATE INDEX `idx_users_status` ON `users` (`status`);
232
- ```
233
-
234
- ---
235
-
236
- ## PostgreSQL 导出
237
-
238
- ### 基本用法
239
-
240
- ```javascript
241
- const { dsl, exporters } = require('schema-dsl');
242
-
243
- const schema = dsl({
244
- id: 'uuid!',
245
- username: 'string:3-32!'
246
- .description('用户登录名'),
247
- email: 'email!'
248
- .description('用户邮箱'),
249
- age: 'number:18-120',
250
- status: 'active|inactive|banned',
251
- metadata: {
252
- lastLogin: 'datetime',
253
- preferences: 'object'
254
- }
255
- });
256
-
257
- const exporter = new exporters.PostgreSQLExporter();
258
- const ddl = exporter.export('users', schema);
259
-
260
- console.log(ddl);
261
- ```
262
-
263
- **输出**:
264
-
265
- ```sql
266
- CREATE TABLE public.users (
267
- id UUID NOT NULL,
268
- username VARCHAR(32) NOT NULL CHECK (LENGTH(username) BETWEEN 3 AND 32),
269
- email VARCHAR(255) NOT NULL,
270
- age DOUBLE PRECISION CHECK (age BETWEEN 18 AND 120),
271
- status VARCHAR(255) CHECK (status IN ('active', 'inactive', 'banned')),
272
- metadata JSONB,
273
- PRIMARY KEY (id)
274
- );
275
-
276
- COMMENT ON COLUMN public.users.username IS '用户登录名';
277
- COMMENT ON COLUMN public.users.email IS '用户邮箱';
278
- ```
279
-
280
- ### 配置选项
281
-
282
- ```javascript
283
- const exporter = new exporters.PostgreSQLExporter({
284
- schema: 'myapp' // PostgreSQL schema 名称
285
- });
286
- ```
287
-
288
- ### 生成索引
289
-
290
- ```javascript
291
- // B-tree 索引(默认)
292
- console.log(exporter.generateIndex('users', 'email', { unique: true }));
293
- // CREATE UNIQUE INDEX idx_users_email ON public.users USING btree (email);
294
-
295
- // GIN 索引(用于 JSONB)
296
- console.log(exporter.generateIndex('users', 'metadata', { method: 'gin' }));
297
- // CREATE INDEX idx_users_metadata ON public.users USING gin (metadata);
298
- ```
299
-
300
- ---
301
-
302
- ## 导出对比
303
-
304
- ### 同一 Schema 的三种导出
305
-
306
- ```javascript
307
- const schema = dsl({
308
- id: 'uuid!',
309
- name: 'string:3-100!',
310
- score: 'number:0-100',
311
- tags: 'array<string>',
312
- active: 'boolean'
313
- });
314
- ```
315
-
316
- | 字段 | MongoDB | MySQL | PostgreSQL |
317
- |------|---------|-------|------------|
318
- | `id` | `bsonType: 'string'` | `VARCHAR(255) NOT NULL` | `UUID NOT NULL` |
319
- | `name` | `bsonType: 'string', minLength: 3, maxLength: 100` | `VARCHAR(100) NOT NULL` | `VARCHAR(100) NOT NULL CHECK (...)` |
320
- | `score` | `bsonType: 'double', minimum: 0, maximum: 100` | `DOUBLE NULL` | `DOUBLE PRECISION CHECK (...)` |
321
- | `tags` | `bsonType: 'array', items: {...}` | `JSON NULL` | `JSONB` |
322
- | `active` | `bsonType: 'bool'` | `BOOLEAN NULL` | `BOOLEAN` |
323
-
324
- ### 约束支持对比
325
-
326
- | 约束类型 | MongoDB | MySQL | PostgreSQL |
327
- |---------|---------|-------|------------|
328
- | NOT NULL | ✅ `required` | ✅ `NOT NULL` | ✅ `NOT NULL` |
329
- | 长度范围 | ✅ `minLength/maxLength` | ❌ | ✅ `CHECK` |
330
- | 数值范围 | ✅ `minimum/maximum` | ❌ | ✅ `CHECK` |
331
- | 枚举 | ✅ `enum` | ❌ | ✅ `CHECK` |
332
- | 正则 | ✅ `pattern` | ❌ | ❌ |
333
- | 默认值 | ❌ | ✅ `DEFAULT` | ✅ `DEFAULT` |
334
- | 注释 | ❌ | ✅ `COMMENT` | ✅ `COMMENT ON` |
335
-
336
- ---
337
-
338
- ## 最佳实践
339
-
340
- ### 1. 使用 description 添加注释
341
-
342
- ```javascript
343
- const schema = dsl({
344
- username: 'string:3-32!'
345
- .description('用户登录名,只能包含字母数字下划线'),
346
- email: 'email!'
347
- .description('用户邮箱,用于登录和接收通知')
348
- });
349
-
350
- // MySQL 和 PostgreSQL 会生成带注释的 DDL
351
- ```
352
-
353
- ### 2. 统一定义,多处导出
354
-
355
- ```javascript
356
- // schemas/user.js
357
- const { dsl } = require('schema-dsl');
358
-
359
- module.exports = dsl({
360
- id: 'uuid!',
361
- username: 'string:3-32!',
362
- email: 'email!',
363
- createdAt: 'datetime!'
364
- });
365
-
366
- // 导出脚本
367
- const { exporters } = require('schema-dsl');
368
- const userSchema = require('./schemas/user');
369
-
370
- // 生成所有数据库的 DDL
371
- const outputs = {
372
- mongo: new exporters.MongoDBExporter().generateCommand('users', userSchema),
373
- mysql: new exporters.MySQLExporter().export('users', userSchema),
374
- postgres: new exporters.PostgreSQLExporter().export('users', userSchema)
375
- };
376
- ```
377
-
378
- ### 3. 自动化迁移脚本
379
-
380
- ```javascript
381
- const fs = require('fs');
382
- const { dsl, exporters } = require('schema-dsl');
383
-
384
- function generateMigration(schemaName, schema) {
385
- const mysql = new exporters.MySQLExporter();
386
- const pg = new exporters.PostgreSQLExporter();
387
-
388
- const timestamp = Date.now();
389
-
390
- // 生成 MySQL 迁移
391
- fs.writeFileSync(
392
- `migrations/${timestamp}_create_${schemaName}.mysql.sql`,
393
- mysql.export(schemaName, schema)
394
- );
395
-
396
- // 生成 PostgreSQL 迁移
397
- fs.writeFileSync(
398
- `migrations/${timestamp}_create_${schemaName}.pg.sql`,
399
- pg.export(schemaName, schema)
400
- );
401
-
402
- console.log(`生成迁移文件: ${schemaName}`);
403
- }
404
-
405
- generateMigration('users', userSchema);
406
- generateMigration('orders', orderSchema);
407
- ```
408
-
409
- ### 4. 版本管理
410
-
411
- ```javascript
412
- // 在 Schema 中添加版本信息
413
- const userSchemaV1 = dsl({ username: 'string!' });
414
- const userSchemaV2 = dsl({ username: 'string:3-32!', email: 'email!' });
415
-
416
- // 导出时标注版本
417
- function exportWithVersion(name, schema, version) {
418
- const ddl = new exporters.MySQLExporter().export(name, schema);
419
- return `-- Schema Version: ${version}\n-- Generated: ${new Date().toISOString()}\n\n${ddl}`;
420
- }
421
- ```
422
-
423
- ---
424
-
425
- ## 完整示例
426
-
427
- ### 电商系统 Schema 导出
428
-
429
- ```javascript
430
- const { dsl, exporters } = require('schema-dsl');
431
- const fs = require('fs');
432
-
433
- // 用户 Schema
434
- const userSchema = dsl({
435
- id: 'uuid!',
436
- username: 'string:3-32!'.description('用户名'),
437
- email: 'email!'.description('邮箱'),
438
- phone: 'string:11'.phone('cn').description('手机号'),
439
- status: 'active|inactive|banned',
440
- createdAt: 'datetime!'
441
- });
442
-
443
- // 商品 Schema
444
- const productSchema = dsl({
445
- id: 'uuid!',
446
- name: 'string:3-200!'.description('商品名称'),
447
- price: 'number:0-'.description('价格'),
448
- stock: 'integer:0-'.description('库存'),
449
- category: 'string:2-50!',
450
- tags: 'array<string>',
451
- active: 'boolean'
452
- });
453
-
454
- // 订单 Schema
455
- const orderSchema = dsl({
456
- id: 'uuid!',
457
- userId: 'uuid!',
458
- items: 'array!1-100',
459
- totalAmount: 'number:0-!',
460
- status: 'pending|paid|shipped|delivered|cancelled',
461
- createdAt: 'datetime!',
462
- updatedAt: 'datetime'
463
- });
464
-
465
- // 导出所有 Schema
466
- const schemas = { users: userSchema, products: productSchema, orders: orderSchema };
467
- const mysqlExporter = new exporters.MySQLExporter();
468
- const pgExporter = new exporters.PostgreSQLExporter({ schema: 'ecommerce' });
469
-
470
- let mysqlDdl = '';
471
- let pgDdl = '';
472
-
473
- for (const [name, schema] of Object.entries(schemas)) {
474
- mysqlDdl += mysqlExporter.export(name, schema) + '\n\n';
475
- pgDdl += pgExporter.export(name, schema) + '\n\n';
476
- }
477
-
478
- fs.writeFileSync('schema.mysql.sql', mysqlDdl);
479
- fs.writeFileSync('schema.pg.sql', pgDdl);
480
-
481
- console.log('导出完成!');
482
- ```
483
-
484
- ---
485
-
486
- ## 相关文档
487
-
488
- - [**导出限制说明**](export-limitations.md) ⚠️ **必读**
489
- - [MongoDB 导出器](mongodb-exporter.md)
490
- - [MySQL 导出器](mysql-exporter.md)
491
- - [PostgreSQL 导出器](postgresql-exporter.md)
492
- - [TypeConverter](type-converter.md)
493
- - [DSL 语法](dsl-syntax.md)
494
-
495
- ---
496
-
497
- ## 对应示例文件
498
-
499
- **示例入口**: [export-guide.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/export-guide.ts)
500
- **说明**: 覆盖同一组 schema 同时导出到 MongoDB、MySQL 和 PostgreSQL 的最小工作流,便于对照多导出器结果。
501
-
1
+ # 导出完整指南
2
+
3
+ > **用途**: Schema 到多种输出格式的完整导出指南
4
+ > **阅读时间**: 10分钟
5
+
6
+ > ⚠️ **重要提示**: 并非所有 schema-dsl 特性都能导出到数据库。请先阅读 [导出限制说明](export-limitations.md) 了解哪些特性不支持导出。
7
+
8
+ ---
9
+
10
+ ## 📑 目录
11
+
12
+ - [概述](#概述)
13
+ - [快速开始](#快速开始)
14
+ - [MongoDB 导出](#mongodb-导出)
15
+ - [MySQL 导出](#mysql-导出)
16
+ - [PostgreSQL 导出](#postgresql-导出)
17
+ - [Markdown 导出](#markdown-导出)
18
+ - [导出对比](#导出对比)
19
+ - [最佳实践](#最佳实践)
20
+
21
+ ---
22
+
23
+ ## 概述
24
+
25
+ schema-dsl 支持将 JSON Schema 导出为多种数据库结构或文档格式,实现“一次定义,多处使用”。
26
+
27
+ ### 支持的导出格式
28
+
29
+ | 类型 | 导出器 | 输出格式 |
30
+ |------|--------|----------|
31
+ | MongoDB | `MongoDBExporter` | `$jsonSchema` 验证文档 |
32
+ | MySQL | `MySQLExporter` | `CREATE TABLE` DDL |
33
+ | PostgreSQL | `PostgreSQLExporter` | `CREATE TABLE` DDL + COMMENT |
34
+ | Markdown | `MarkdownExporter` | 面向人类阅读的 Markdown 文档 |
35
+
36
+ 其中 `MarkdownExporter` 更适合生成接口字段说明、表单文档或内部规范文档,完整用法见 [Markdown 导出器](./markdown-exporter.md)。
37
+
38
+ ---
39
+
40
+ ## 快速开始
41
+
42
+ ```javascript
43
+ const { dsl, exporters } = require('schema-dsl');
44
+
45
+ // 定义统一的 Schema
46
+ const userSchema = dsl({
47
+ id: 'uuid!',
48
+ username: 'string:3-32!'
49
+ .pattern(/^[a-zA-Z0-9_]+$/)
50
+ .description('用户登录名'),
51
+ email: 'email!'
52
+ .description('用户邮箱'),
53
+ age: 'number:18-120',
54
+ status: 'active|inactive|banned',
55
+ createdAt: 'datetime!'
56
+ });
57
+
58
+ // 导出到不同目标
59
+ const mongoSchema = new exporters.MongoDBExporter().export(userSchema);
60
+ const mysqlDdl = new exporters.MySQLExporter().export('users', userSchema);
61
+ const pgDdl = new exporters.PostgreSQLExporter().export('users', userSchema);
62
+ const markdownDoc = exporters.MarkdownExporter.export(userSchema, {
63
+ title: '用户 Schema 文档'
64
+ });
65
+ ```
66
+
67
+ ---
68
+
69
+ ## Markdown 导出
70
+
71
+ 如果你的目标不是数据库,而是给研发、测试、产品或接口使用方生成一份可直接阅读的字段说明文档,可以使用 `MarkdownExporter`:
72
+
73
+ ```javascript
74
+ const { dsl, exporters } = require('schema-dsl');
75
+
76
+ const schema = dsl({
77
+ username: 'string:3-32!'.description('登录账号'),
78
+ email: 'email!'.description('联系邮箱'),
79
+ age: 'number:18-120'.description('年龄')
80
+ });
81
+
82
+ const markdown = exporters.MarkdownExporter.export(schema, {
83
+ title: '用户注册字段说明',
84
+ locale: 'zh-CN'
85
+ });
86
+
87
+ console.log(markdown);
88
+ ```
89
+
90
+ 更完整的选项、示例和多语言输出说明见 [Markdown 导出器](./markdown-exporter.md)。
91
+
92
+ ---
93
+
94
+ ## MongoDB 导出
95
+
96
+ ### 基本用法
97
+
98
+ ```javascript
99
+ const { dsl, exporters } = require('schema-dsl');
100
+
101
+ const schema = dsl({
102
+ username: 'string:3-32!',
103
+ email: 'email!',
104
+ age: 'number:18-120'
105
+ });
106
+
107
+ const exporter = new exporters.MongoDBExporter();
108
+ const mongoSchema = exporter.export(schema);
109
+
110
+ console.log(JSON.stringify(mongoSchema, null, 2));
111
+ ```
112
+
113
+ **输出**:
114
+
115
+ ```json
116
+ {
117
+ "$jsonSchema": {
118
+ "bsonType": "object",
119
+ "required": ["username", "email"],
120
+ "properties": {
121
+ "username": {
122
+ "bsonType": "string",
123
+ "minLength": 3,
124
+ "maxLength": 32
125
+ },
126
+ "email": {
127
+ "bsonType": "string"
128
+ },
129
+ "age": {
130
+ "bsonType": "double",
131
+ "minimum": 18,
132
+ "maximum": 120
133
+ }
134
+ }
135
+ }
136
+ }
137
+ ```
138
+
139
+ ### 生成创建命令
140
+
141
+ ```javascript
142
+ const command = exporter.generateCommand('users', schema);
143
+ console.log(command);
144
+ ```
145
+
146
+ **输出**:
147
+
148
+ ```javascript
149
+ db.createCollection("users", {
150
+ "validator": {
151
+ "$jsonSchema": { ... }
152
+ },
153
+ "validationLevel": "moderate",
154
+ "validationAction": "error"
155
+ })
156
+ ```
157
+
158
+ ### 在 MongoDB 中使用
159
+
160
+ ```javascript
161
+ const { MongoClient } = require('mongodb');
162
+
163
+ async function setupCollection() {
164
+ const client = new MongoClient('mongodb://localhost:27017');
165
+ await client.connect();
166
+
167
+ const db = client.db('myapp');
168
+ const exporter = new exporters.MongoDBExporter({ strict: true });
169
+ const { options } = exporter.generateCreateCommand('users', schema);
170
+
171
+ await db.createCollection('users', options);
172
+ console.log('创建带验证的集合成功');
173
+ }
174
+ ```
175
+
176
+ ---
177
+
178
+ ## MySQL 导出
179
+
180
+ ### 基本用法
181
+
182
+ ```javascript
183
+ const { dsl, exporters } = require('schema-dsl');
184
+
185
+ const schema = dsl({
186
+ id: 'string!',
187
+ username: 'string:3-32!',
188
+ email: 'email!',
189
+ age: 'number:0-150',
190
+ status: 'active|inactive'
191
+ });
192
+
193
+ const exporter = new exporters.MySQLExporter();
194
+ const ddl = exporter.export('users', schema);
195
+
196
+ console.log(ddl);
197
+ ```
198
+
199
+ **输出**:
200
+
201
+ ```sql
202
+ CREATE TABLE `users` (
203
+ `id` VARCHAR(255) NOT NULL,
204
+ `username` VARCHAR(32) NOT NULL,
205
+ `email` VARCHAR(255) NOT NULL,
206
+ `age` DOUBLE NULL,
207
+ `status` VARCHAR(255) NULL,
208
+ PRIMARY KEY (`id`)
209
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
210
+ ```
211
+
212
+ ### 配置选项
213
+
214
+ ```javascript
215
+ const exporter = new exporters.MySQLExporter({
216
+ engine: 'InnoDB', // 存储引擎
217
+ charset: 'utf8mb4', // 字符集
218
+ collate: 'utf8mb4_unicode_ci' // 排序规则
219
+ });
220
+ ```
221
+
222
+ ### 生成索引
223
+
224
+ ```javascript
225
+ // 唯一索引
226
+ console.log(exporter.generateIndex('users', 'email', { unique: true }));
227
+ // CREATE UNIQUE INDEX `idx_users_email` ON `users` (`email`);
228
+
229
+ // 普通索引
230
+ console.log(exporter.generateIndex('users', 'status'));
231
+ // CREATE INDEX `idx_users_status` ON `users` (`status`);
232
+ ```
233
+
234
+ ---
235
+
236
+ ## PostgreSQL 导出
237
+
238
+ ### 基本用法
239
+
240
+ ```javascript
241
+ const { dsl, exporters } = require('schema-dsl');
242
+
243
+ const schema = dsl({
244
+ id: 'uuid!',
245
+ username: 'string:3-32!'
246
+ .description('用户登录名'),
247
+ email: 'email!'
248
+ .description('用户邮箱'),
249
+ age: 'number:18-120',
250
+ status: 'active|inactive|banned',
251
+ metadata: {
252
+ lastLogin: 'datetime',
253
+ preferences: 'object'
254
+ }
255
+ });
256
+
257
+ const exporter = new exporters.PostgreSQLExporter();
258
+ const ddl = exporter.export('users', schema);
259
+
260
+ console.log(ddl);
261
+ ```
262
+
263
+ **输出**:
264
+
265
+ ```sql
266
+ CREATE TABLE public.users (
267
+ id UUID NOT NULL,
268
+ username VARCHAR(32) NOT NULL CHECK (LENGTH(username) BETWEEN 3 AND 32),
269
+ email VARCHAR(255) NOT NULL,
270
+ age DOUBLE PRECISION CHECK (age BETWEEN 18 AND 120),
271
+ status VARCHAR(255) CHECK (status IN ('active', 'inactive', 'banned')),
272
+ metadata JSONB,
273
+ PRIMARY KEY (id)
274
+ );
275
+
276
+ COMMENT ON COLUMN public.users.username IS '用户登录名';
277
+ COMMENT ON COLUMN public.users.email IS '用户邮箱';
278
+ ```
279
+
280
+ ### 配置选项
281
+
282
+ ```javascript
283
+ const exporter = new exporters.PostgreSQLExporter({
284
+ schema: 'myapp' // PostgreSQL schema 名称
285
+ });
286
+ ```
287
+
288
+ ### 生成索引
289
+
290
+ ```javascript
291
+ // B-tree 索引(默认)
292
+ console.log(exporter.generateIndex('users', 'email', { unique: true }));
293
+ // CREATE UNIQUE INDEX idx_users_email ON public.users USING btree (email);
294
+
295
+ // GIN 索引(用于 JSONB)
296
+ console.log(exporter.generateIndex('users', 'metadata', { method: 'gin' }));
297
+ // CREATE INDEX idx_users_metadata ON public.users USING gin (metadata);
298
+ ```
299
+
300
+ ---
301
+
302
+ ## 导出对比
303
+
304
+ ### 同一 Schema 的三种导出
305
+
306
+ ```javascript
307
+ const schema = dsl({
308
+ id: 'uuid!',
309
+ name: 'string:3-100!',
310
+ score: 'number:0-100',
311
+ tags: 'array<string>',
312
+ active: 'boolean'
313
+ });
314
+ ```
315
+
316
+ | 字段 | MongoDB | MySQL | PostgreSQL |
317
+ |------|---------|-------|------------|
318
+ | `id` | `bsonType: 'string'` | `VARCHAR(255) NOT NULL` | `UUID NOT NULL` |
319
+ | `name` | `bsonType: 'string', minLength: 3, maxLength: 100` | `VARCHAR(100) NOT NULL` | `VARCHAR(100) NOT NULL CHECK (...)` |
320
+ | `score` | `bsonType: 'double', minimum: 0, maximum: 100` | `DOUBLE NULL` | `DOUBLE PRECISION CHECK (...)` |
321
+ | `tags` | `bsonType: 'array', items: {...}` | `JSON NULL` | `JSONB` |
322
+ | `active` | `bsonType: 'bool'` | `BOOLEAN NULL` | `BOOLEAN` |
323
+
324
+ ### 约束支持对比
325
+
326
+ | 约束类型 | MongoDB | MySQL | PostgreSQL |
327
+ |---------|---------|-------|------------|
328
+ | NOT NULL | ✅ `required` | ✅ `NOT NULL` | ✅ `NOT NULL` |
329
+ | 长度范围 | ✅ `minLength/maxLength` | ❌ | ✅ `CHECK` |
330
+ | 数值范围 | ✅ `minimum/maximum` | ❌ | ✅ `CHECK` |
331
+ | 枚举 | ✅ `enum` | ❌ | ✅ `CHECK` |
332
+ | 正则 | ✅ `pattern` | ❌ | ❌ |
333
+ | 默认值 | ❌ | ✅ `DEFAULT` | ✅ `DEFAULT` |
334
+ | 注释 | ❌ | ✅ `COMMENT` | ✅ `COMMENT ON` |
335
+
336
+ ---
337
+
338
+ ## 最佳实践
339
+
340
+ ### 1. 使用 description 添加注释
341
+
342
+ ```javascript
343
+ const schema = dsl({
344
+ username: 'string:3-32!'
345
+ .description('用户登录名,只能包含字母数字下划线'),
346
+ email: 'email!'
347
+ .description('用户邮箱,用于登录和接收通知')
348
+ });
349
+
350
+ // MySQL 和 PostgreSQL 会生成带注释的 DDL
351
+ ```
352
+
353
+ ### 2. 统一定义,多处导出
354
+
355
+ ```javascript
356
+ // schemas/user.js
357
+ const { dsl } = require('schema-dsl');
358
+
359
+ module.exports = dsl({
360
+ id: 'uuid!',
361
+ username: 'string:3-32!',
362
+ email: 'email!',
363
+ createdAt: 'datetime!'
364
+ });
365
+
366
+ // 导出脚本
367
+ const { exporters } = require('schema-dsl');
368
+ const userSchema = require('./schemas/user');
369
+
370
+ // 生成所有数据库的 DDL
371
+ const outputs = {
372
+ mongo: new exporters.MongoDBExporter().generateCommand('users', userSchema),
373
+ mysql: new exporters.MySQLExporter().export('users', userSchema),
374
+ postgres: new exporters.PostgreSQLExporter().export('users', userSchema)
375
+ };
376
+ ```
377
+
378
+ ### 3. 自动化迁移脚本
379
+
380
+ ```javascript
381
+ const fs = require('fs');
382
+ const { dsl, exporters } = require('schema-dsl');
383
+
384
+ function generateMigration(schemaName, schema) {
385
+ const mysql = new exporters.MySQLExporter();
386
+ const pg = new exporters.PostgreSQLExporter();
387
+
388
+ const timestamp = Date.now();
389
+
390
+ // 生成 MySQL 迁移
391
+ fs.writeFileSync(
392
+ `migrations/${timestamp}_create_${schemaName}.mysql.sql`,
393
+ mysql.export(schemaName, schema)
394
+ );
395
+
396
+ // 生成 PostgreSQL 迁移
397
+ fs.writeFileSync(
398
+ `migrations/${timestamp}_create_${schemaName}.pg.sql`,
399
+ pg.export(schemaName, schema)
400
+ );
401
+
402
+ console.log(`生成迁移文件: ${schemaName}`);
403
+ }
404
+
405
+ generateMigration('users', userSchema);
406
+ generateMigration('orders', orderSchema);
407
+ ```
408
+
409
+ ### 4. 版本管理
410
+
411
+ ```javascript
412
+ // 在 Schema 中添加版本信息
413
+ const userSchemaV1 = dsl({ username: 'string!' });
414
+ const userSchemaV2 = dsl({ username: 'string:3-32!', email: 'email!' });
415
+
416
+ // 导出时标注版本
417
+ function exportWithVersion(name, schema, version) {
418
+ const ddl = new exporters.MySQLExporter().export(name, schema);
419
+ return `-- Schema Version: ${version}\n-- Generated: ${new Date().toISOString()}\n\n${ddl}`;
420
+ }
421
+ ```
422
+
423
+ ---
424
+
425
+ ## 完整示例
426
+
427
+ ### 电商系统 Schema 导出
428
+
429
+ ```javascript
430
+ const { dsl, exporters } = require('schema-dsl');
431
+ const fs = require('fs');
432
+
433
+ // 用户 Schema
434
+ const userSchema = dsl({
435
+ id: 'uuid!',
436
+ username: 'string:3-32!'.description('用户名'),
437
+ email: 'email!'.description('邮箱'),
438
+ phone: 'string:11'.phone('cn').description('手机号'),
439
+ status: 'active|inactive|banned',
440
+ createdAt: 'datetime!'
441
+ });
442
+
443
+ // 商品 Schema
444
+ const productSchema = dsl({
445
+ id: 'uuid!',
446
+ name: 'string:3-200!'.description('商品名称'),
447
+ price: 'number:0-'.description('价格'),
448
+ stock: 'integer:0-'.description('库存'),
449
+ category: 'string:2-50!',
450
+ tags: 'array<string>',
451
+ active: 'boolean'
452
+ });
453
+
454
+ // 订单 Schema
455
+ const orderSchema = dsl({
456
+ id: 'uuid!',
457
+ userId: 'uuid!',
458
+ items: 'array!1-100',
459
+ totalAmount: 'number:0-!',
460
+ status: 'pending|paid|shipped|delivered|cancelled',
461
+ createdAt: 'datetime!',
462
+ updatedAt: 'datetime'
463
+ });
464
+
465
+ // 导出所有 Schema
466
+ const schemas = { users: userSchema, products: productSchema, orders: orderSchema };
467
+ const mysqlExporter = new exporters.MySQLExporter();
468
+ const pgExporter = new exporters.PostgreSQLExporter({ schema: 'ecommerce' });
469
+
470
+ let mysqlDdl = '';
471
+ let pgDdl = '';
472
+
473
+ for (const [name, schema] of Object.entries(schemas)) {
474
+ mysqlDdl += mysqlExporter.export(name, schema) + '\n\n';
475
+ pgDdl += pgExporter.export(name, schema) + '\n\n';
476
+ }
477
+
478
+ fs.writeFileSync('schema.mysql.sql', mysqlDdl);
479
+ fs.writeFileSync('schema.pg.sql', pgDdl);
480
+
481
+ console.log('导出完成!');
482
+ ```
483
+
484
+ ---
485
+
486
+ ## 相关文档
487
+
488
+ - [**导出限制说明**](export-limitations.md) ⚠️ **必读**
489
+ - [MongoDB 导出器](mongodb-exporter.md)
490
+ - [MySQL 导出器](mysql-exporter.md)
491
+ - [PostgreSQL 导出器](postgresql-exporter.md)
492
+ - [TypeConverter](type-converter.md)
493
+ - [DSL 语法](dsl-syntax.md)
494
+
495
+ ---
496
+
497
+ ## 对应示例文件
498
+
499
+ **示例入口**: [export-guide.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/export-guide.ts)
500
+ **说明**: 覆盖同一组 schema 同时导出到 MongoDB、MySQL 和 PostgreSQL 的最小工作流,便于对照多导出器结果。
501
+