schema-dsl 2.3.0

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 (109) hide show
  1. package/.eslintignore +10 -0
  2. package/.eslintrc.json +27 -0
  3. package/.github/CODE_OF_CONDUCT.md +45 -0
  4. package/.github/ISSUE_TEMPLATE/bug_report.md +57 -0
  5. package/.github/ISSUE_TEMPLATE/config.yml +11 -0
  6. package/.github/ISSUE_TEMPLATE/feature_request.md +45 -0
  7. package/.github/ISSUE_TEMPLATE/question.md +31 -0
  8. package/.github/PULL_REQUEST_TEMPLATE.md +70 -0
  9. package/.github/SECURITY.md +184 -0
  10. package/.github/workflows/ci.yml +35 -0
  11. package/CHANGELOG.md +633 -0
  12. package/CONTRIBUTING.md +368 -0
  13. package/LICENSE +21 -0
  14. package/README.md +1122 -0
  15. package/STATUS.md +273 -0
  16. package/docs/FEATURE-INDEX.md +521 -0
  17. package/docs/INDEX.md +224 -0
  18. package/docs/api-reference.md +1098 -0
  19. package/docs/best-practices.md +672 -0
  20. package/docs/cache-manager.md +336 -0
  21. package/docs/design-philosophy.md +602 -0
  22. package/docs/dsl-syntax.md +654 -0
  23. package/docs/dynamic-locale.md +552 -0
  24. package/docs/error-handling.md +703 -0
  25. package/docs/export-guide.md +459 -0
  26. package/docs/faq.md +576 -0
  27. package/docs/frontend-i18n-guide.md +290 -0
  28. package/docs/i18n-user-guide.md +488 -0
  29. package/docs/label-vs-description.md +262 -0
  30. package/docs/markdown-exporter.md +398 -0
  31. package/docs/mongodb-exporter.md +279 -0
  32. package/docs/multi-type-support.md +319 -0
  33. package/docs/mysql-exporter.md +257 -0
  34. package/docs/plugin-system.md +542 -0
  35. package/docs/postgresql-exporter.md +290 -0
  36. package/docs/quick-start.md +761 -0
  37. package/docs/schema-helper.md +340 -0
  38. package/docs/schema-utils.md +492 -0
  39. package/docs/string-extensions.md +480 -0
  40. package/docs/troubleshooting.md +471 -0
  41. package/docs/type-converter.md +319 -0
  42. package/docs/type-reference.md +219 -0
  43. package/docs/validate.md +486 -0
  44. package/docs/validation-guide.md +484 -0
  45. package/examples/array-dsl-example.js +227 -0
  46. package/examples/custom-extension.js +85 -0
  47. package/examples/dsl-match-example.js +74 -0
  48. package/examples/dsl-style.js +118 -0
  49. package/examples/dynamic-locale-configuration.js +348 -0
  50. package/examples/dynamic-locale-example.js +287 -0
  51. package/examples/export-demo.js +130 -0
  52. package/examples/i18n-full-demo.js +310 -0
  53. package/examples/i18n-memory-safety.examples.js +268 -0
  54. package/examples/markdown-export.js +71 -0
  55. package/examples/middleware-usage.js +93 -0
  56. package/examples/password-reset/README.md +153 -0
  57. package/examples/password-reset/schema.js +26 -0
  58. package/examples/password-reset/test.js +101 -0
  59. package/examples/plugin-system.examples.js +205 -0
  60. package/examples/simple-example.js +122 -0
  61. package/examples/string-extensions.js +297 -0
  62. package/examples/user-registration/README.md +156 -0
  63. package/examples/user-registration/routes.js +92 -0
  64. package/examples/user-registration/schema.js +150 -0
  65. package/examples/user-registration/server.js +74 -0
  66. package/index.d.ts +1999 -0
  67. package/index.js +270 -0
  68. package/index.mjs +30 -0
  69. package/lib/adapters/DslAdapter.js +653 -0
  70. package/lib/adapters/index.js +20 -0
  71. package/lib/config/constants.js +286 -0
  72. package/lib/config/patterns/creditCard.js +9 -0
  73. package/lib/config/patterns/idCard.js +9 -0
  74. package/lib/config/patterns/index.js +8 -0
  75. package/lib/config/patterns/licensePlate.js +4 -0
  76. package/lib/config/patterns/passport.js +4 -0
  77. package/lib/config/patterns/phone.js +9 -0
  78. package/lib/config/patterns/postalCode.js +5 -0
  79. package/lib/core/CacheManager.js +376 -0
  80. package/lib/core/DslBuilder.js +740 -0
  81. package/lib/core/ErrorCodes.js +233 -0
  82. package/lib/core/ErrorFormatter.js +342 -0
  83. package/lib/core/JSONSchemaCore.js +347 -0
  84. package/lib/core/Locale.js +119 -0
  85. package/lib/core/MessageTemplate.js +89 -0
  86. package/lib/core/PluginManager.js +448 -0
  87. package/lib/core/StringExtensions.js +209 -0
  88. package/lib/core/Validator.js +316 -0
  89. package/lib/exporters/MarkdownExporter.js +420 -0
  90. package/lib/exporters/MongoDBExporter.js +162 -0
  91. package/lib/exporters/MySQLExporter.js +212 -0
  92. package/lib/exporters/PostgreSQLExporter.js +289 -0
  93. package/lib/exporters/index.js +24 -0
  94. package/lib/locales/en-US.js +65 -0
  95. package/lib/locales/es-ES.js +66 -0
  96. package/lib/locales/fr-FR.js +66 -0
  97. package/lib/locales/index.js +8 -0
  98. package/lib/locales/ja-JP.js +66 -0
  99. package/lib/locales/zh-CN.js +93 -0
  100. package/lib/utils/LRUCache.js +174 -0
  101. package/lib/utils/SchemaHelper.js +240 -0
  102. package/lib/utils/SchemaUtils.js +313 -0
  103. package/lib/utils/TypeConverter.js +245 -0
  104. package/lib/utils/index.js +13 -0
  105. package/lib/validators/CustomKeywords.js +203 -0
  106. package/lib/validators/index.js +11 -0
  107. package/package.json +70 -0
  108. package/plugins/custom-format.js +101 -0
  109. package/plugins/custom-validator.js +200 -0
@@ -0,0 +1,459 @@
1
+ # 数据库导出完整指南
2
+
3
+ > **用途**: Schema 到数据库 DDL 的完整导出指南
4
+ > **阅读时间**: 10分钟
5
+
6
+ ---
7
+
8
+ ## 📑 目录
9
+
10
+ - [概述](#概述)
11
+ - [快速开始](#快速开始)
12
+ - [MongoDB 导出](#mongodb-导出)
13
+ - [MySQL 导出](#mysql-导出)
14
+ - [PostgreSQL 导出](#postgresql-导出)
15
+ - [导出对比](#导出对比)
16
+ - [最佳实践](#最佳实践)
17
+
18
+ ---
19
+
20
+ ## 概述
21
+
22
+ SchemaIO 支持将 JSON Schema 导出为多种数据库的 DDL 语句,实现"一次定义,多处使用"。
23
+
24
+ ### 支持的数据库
25
+
26
+ | 数据库 | 导出器 | 输出格式 |
27
+ |--------|--------|----------|
28
+ | MongoDB | `MongoDBExporter` | `$jsonSchema` 验证文档 |
29
+ | MySQL | `MySQLExporter` | `CREATE TABLE` DDL |
30
+ | PostgreSQL | `PostgreSQLExporter` | `CREATE TABLE` DDL + COMMENT |
31
+
32
+ ---
33
+
34
+ ## 快速开始
35
+
36
+ ```javascript
37
+ const { dsl, exporters } = require('schema-dsl');
38
+
39
+ // 定义统一的 Schema
40
+ const userSchema = dsl({
41
+ id: 'uuid!',
42
+ username: 'string:3-32!'
43
+ .pattern(/^[a-zA-Z0-9_]+$/)
44
+ .description('用户登录名'),
45
+ email: 'email!'
46
+ .description('用户邮箱'),
47
+ age: 'number:18-120',
48
+ status: 'active|inactive|banned',
49
+ createdAt: 'datetime!'
50
+ });
51
+
52
+ // 导出到不同数据库
53
+ const mongoSchema = new exporters.MongoDBExporter().export(userSchema);
54
+ const mysqlDdl = new exporters.MySQLExporter().export('users', userSchema);
55
+ const pgDdl = new exporters.PostgreSQLExporter().export('users', userSchema);
56
+ ```
57
+
58
+ ---
59
+
60
+ ## MongoDB 导出
61
+
62
+ ### 基本用法
63
+
64
+ ```javascript
65
+ const { dsl, exporters } = require('schema-dsl');
66
+
67
+ const schema = dsl({
68
+ username: 'string:3-32!',
69
+ email: 'email!',
70
+ age: 'number:18-120'
71
+ });
72
+
73
+ const exporter = new exporters.MongoDBExporter();
74
+ const mongoSchema = exporter.export(schema);
75
+
76
+ console.log(JSON.stringify(mongoSchema, null, 2));
77
+ ```
78
+
79
+ **输出**:
80
+
81
+ ```json
82
+ {
83
+ "$jsonSchema": {
84
+ "bsonType": "object",
85
+ "required": ["username", "email"],
86
+ "properties": {
87
+ "username": {
88
+ "bsonType": "string",
89
+ "minLength": 3,
90
+ "maxLength": 32
91
+ },
92
+ "email": {
93
+ "bsonType": "string"
94
+ },
95
+ "age": {
96
+ "bsonType": "double",
97
+ "minimum": 18,
98
+ "maximum": 120
99
+ }
100
+ }
101
+ }
102
+ }
103
+ ```
104
+
105
+ ### 生成创建命令
106
+
107
+ ```javascript
108
+ const command = exporter.generateCommand('users', schema);
109
+ console.log(command);
110
+ ```
111
+
112
+ **输出**:
113
+
114
+ ```javascript
115
+ db.createCollection("users", {
116
+ "validator": {
117
+ "$jsonSchema": { ... }
118
+ },
119
+ "validationLevel": "moderate",
120
+ "validationAction": "error"
121
+ })
122
+ ```
123
+
124
+ ### 在 MongoDB 中使用
125
+
126
+ ```javascript
127
+ const { MongoClient } = require('mongodb');
128
+
129
+ async function setupCollection() {
130
+ const client = new MongoClient('mongodb://localhost:27017');
131
+ await client.connect();
132
+
133
+ const db = client.db('myapp');
134
+ const exporter = new exporters.MongoDBExporter({ strict: true });
135
+ const { options } = exporter.generateCreateCommand('users', schema);
136
+
137
+ await db.createCollection('users', options);
138
+ console.log('创建带验证的集合成功');
139
+ }
140
+ ```
141
+
142
+ ---
143
+
144
+ ## MySQL 导出
145
+
146
+ ### 基本用法
147
+
148
+ ```javascript
149
+ const { dsl, exporters } = require('schema-dsl');
150
+
151
+ const schema = dsl({
152
+ id: 'string!',
153
+ username: 'string:3-32!',
154
+ email: 'email!',
155
+ age: 'number:0-150',
156
+ status: 'active|inactive'
157
+ });
158
+
159
+ const exporter = new exporters.MySQLExporter();
160
+ const ddl = exporter.export('users', schema);
161
+
162
+ console.log(ddl);
163
+ ```
164
+
165
+ **输出**:
166
+
167
+ ```sql
168
+ CREATE TABLE `users` (
169
+ `id` VARCHAR(255) NOT NULL,
170
+ `username` VARCHAR(32) NOT NULL,
171
+ `email` VARCHAR(255) NOT NULL,
172
+ `age` DOUBLE NULL,
173
+ `status` VARCHAR(255) NULL,
174
+ PRIMARY KEY (`id`)
175
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
176
+ ```
177
+
178
+ ### 配置选项
179
+
180
+ ```javascript
181
+ const exporter = new exporters.MySQLExporter({
182
+ engine: 'InnoDB', // 存储引擎
183
+ charset: 'utf8mb4', // 字符集
184
+ collate: 'utf8mb4_unicode_ci' // 排序规则
185
+ });
186
+ ```
187
+
188
+ ### 生成索引
189
+
190
+ ```javascript
191
+ // 唯一索引
192
+ console.log(exporter.generateIndex('users', 'email', { unique: true }));
193
+ // CREATE UNIQUE INDEX `idx_users_email` ON `users` (`email`);
194
+
195
+ // 普通索引
196
+ console.log(exporter.generateIndex('users', 'status'));
197
+ // CREATE INDEX `idx_users_status` ON `users` (`status`);
198
+ ```
199
+
200
+ ---
201
+
202
+ ## PostgreSQL 导出
203
+
204
+ ### 基本用法
205
+
206
+ ```javascript
207
+ const { dsl, exporters } = require('schema-dsl');
208
+
209
+ const schema = dsl({
210
+ id: 'uuid!',
211
+ username: 'string:3-32!'
212
+ .description('用户登录名'),
213
+ email: 'email!'
214
+ .description('用户邮箱'),
215
+ age: 'number:18-120',
216
+ status: 'active|inactive|banned',
217
+ metadata: {
218
+ lastLogin: 'datetime',
219
+ preferences: 'object'
220
+ }
221
+ });
222
+
223
+ const exporter = new exporters.PostgreSQLExporter();
224
+ const ddl = exporter.export('users', schema);
225
+
226
+ console.log(ddl);
227
+ ```
228
+
229
+ **输出**:
230
+
231
+ ```sql
232
+ CREATE TABLE public.users (
233
+ id UUID NOT NULL,
234
+ username VARCHAR(32) NOT NULL CHECK (LENGTH(username) BETWEEN 3 AND 32),
235
+ email VARCHAR(255) NOT NULL,
236
+ age DOUBLE PRECISION CHECK (age BETWEEN 18 AND 120),
237
+ status VARCHAR(255) CHECK (status IN ('active', 'inactive', 'banned')),
238
+ metadata JSONB,
239
+ PRIMARY KEY (id)
240
+ );
241
+
242
+ COMMENT ON COLUMN public.users.username IS '用户登录名';
243
+ COMMENT ON COLUMN public.users.email IS '用户邮箱';
244
+ ```
245
+
246
+ ### 配置选项
247
+
248
+ ```javascript
249
+ const exporter = new exporters.PostgreSQLExporter({
250
+ schema: 'myapp' // PostgreSQL schema 名称
251
+ });
252
+ ```
253
+
254
+ ### 生成索引
255
+
256
+ ```javascript
257
+ // B-tree 索引(默认)
258
+ console.log(exporter.generateIndex('users', 'email', { unique: true }));
259
+ // CREATE UNIQUE INDEX idx_users_email ON public.users USING btree (email);
260
+
261
+ // GIN 索引(用于 JSONB)
262
+ console.log(exporter.generateIndex('users', 'metadata', { method: 'gin' }));
263
+ // CREATE INDEX idx_users_metadata ON public.users USING gin (metadata);
264
+ ```
265
+
266
+ ---
267
+
268
+ ## 导出对比
269
+
270
+ ### 同一 Schema 的三种导出
271
+
272
+ ```javascript
273
+ const schema = dsl({
274
+ id: 'uuid!',
275
+ name: 'string:3-100!',
276
+ score: 'number:0-100',
277
+ tags: 'array<string>',
278
+ active: 'boolean'
279
+ });
280
+ ```
281
+
282
+ | 字段 | MongoDB | MySQL | PostgreSQL |
283
+ |------|---------|-------|------------|
284
+ | `id` | `bsonType: 'string'` | `VARCHAR(255) NOT NULL` | `UUID NOT NULL` |
285
+ | `name` | `bsonType: 'string', minLength: 3, maxLength: 100` | `VARCHAR(100) NOT NULL` | `VARCHAR(100) NOT NULL CHECK (...)` |
286
+ | `score` | `bsonType: 'double', minimum: 0, maximum: 100` | `DOUBLE NULL` | `DOUBLE PRECISION CHECK (...)` |
287
+ | `tags` | `bsonType: 'array', items: {...}` | `JSON NULL` | `JSONB` |
288
+ | `active` | `bsonType: 'bool'` | `BOOLEAN NULL` | `BOOLEAN` |
289
+
290
+ ### 约束支持对比
291
+
292
+ | 约束类型 | MongoDB | MySQL | PostgreSQL |
293
+ |---------|---------|-------|------------|
294
+ | NOT NULL | ✅ `required` | ✅ `NOT NULL` | ✅ `NOT NULL` |
295
+ | 长度范围 | ✅ `minLength/maxLength` | ❌ | ✅ `CHECK` |
296
+ | 数值范围 | ✅ `minimum/maximum` | ❌ | ✅ `CHECK` |
297
+ | 枚举 | ✅ `enum` | ❌ | ✅ `CHECK` |
298
+ | 正则 | ✅ `pattern` | ❌ | ❌ |
299
+ | 默认值 | ❌ | ✅ `DEFAULT` | ✅ `DEFAULT` |
300
+ | 注释 | ❌ | ✅ `COMMENT` | ✅ `COMMENT ON` |
301
+
302
+ ---
303
+
304
+ ## 最佳实践
305
+
306
+ ### 1. 使用 description 添加注释
307
+
308
+ ```javascript
309
+ const schema = dsl({
310
+ username: 'string:3-32!'
311
+ .description('用户登录名,只能包含字母数字下划线'),
312
+ email: 'email!'
313
+ .description('用户邮箱,用于登录和接收通知')
314
+ });
315
+
316
+ // MySQL 和 PostgreSQL 会生成带注释的 DDL
317
+ ```
318
+
319
+ ### 2. 统一定义,多处导出
320
+
321
+ ```javascript
322
+ // schemas/user.js
323
+ const { dsl } = require('schema-dsl');
324
+
325
+ module.exports = dsl({
326
+ id: 'uuid!',
327
+ username: 'string:3-32!',
328
+ email: 'email!',
329
+ createdAt: 'datetime!'
330
+ });
331
+
332
+ // 导出脚本
333
+ const { exporters } = require('schema-dsl');
334
+ const userSchema = require('./schemas/user');
335
+
336
+ // 生成所有数据库的 DDL
337
+ const outputs = {
338
+ mongo: new exporters.MongoDBExporter().generateCommand('users', userSchema),
339
+ mysql: new exporters.MySQLExporter().export('users', userSchema),
340
+ postgres: new exporters.PostgreSQLExporter().export('users', userSchema)
341
+ };
342
+ ```
343
+
344
+ ### 3. 自动化迁移脚本
345
+
346
+ ```javascript
347
+ const fs = require('fs');
348
+ const { dsl, exporters } = require('schema-dsl');
349
+
350
+ function generateMigration(schemaName, schema) {
351
+ const mysql = new exporters.MySQLExporter();
352
+ const pg = new exporters.PostgreSQLExporter();
353
+
354
+ const timestamp = Date.now();
355
+
356
+ // 生成 MySQL 迁移
357
+ fs.writeFileSync(
358
+ `migrations/${timestamp}_create_${schemaName}.mysql.sql`,
359
+ mysql.export(schemaName, schema)
360
+ );
361
+
362
+ // 生成 PostgreSQL 迁移
363
+ fs.writeFileSync(
364
+ `migrations/${timestamp}_create_${schemaName}.pg.sql`,
365
+ pg.export(schemaName, schema)
366
+ );
367
+
368
+ console.log(`生成迁移文件: ${schemaName}`);
369
+ }
370
+
371
+ generateMigration('users', userSchema);
372
+ generateMigration('orders', orderSchema);
373
+ ```
374
+
375
+ ### 4. 版本管理
376
+
377
+ ```javascript
378
+ // 在 Schema 中添加版本信息
379
+ const userSchemaV1 = dsl({ username: 'string!' });
380
+ const userSchemaV2 = dsl({ username: 'string:3-32!', email: 'email!' });
381
+
382
+ // 导出时标注版本
383
+ function exportWithVersion(name, schema, version) {
384
+ const ddl = new exporters.MySQLExporter().export(name, schema);
385
+ return `-- Schema Version: ${version}\n-- Generated: ${new Date().toISOString()}\n\n${ddl}`;
386
+ }
387
+ ```
388
+
389
+ ---
390
+
391
+ ## 完整示例
392
+
393
+ ### 电商系统 Schema 导出
394
+
395
+ ```javascript
396
+ const { dsl, exporters } = require('schema-dsl');
397
+ const fs = require('fs');
398
+
399
+ // 用户 Schema
400
+ const userSchema = dsl({
401
+ id: 'uuid!',
402
+ username: 'string:3-32!'.description('用户名'),
403
+ email: 'email!'.description('邮箱'),
404
+ phone: 'string:11'.phone('cn').description('手机号'),
405
+ status: 'active|inactive|banned',
406
+ createdAt: 'datetime!'
407
+ });
408
+
409
+ // 商品 Schema
410
+ const productSchema = dsl({
411
+ id: 'uuid!',
412
+ name: 'string:3-200!'.description('商品名称'),
413
+ price: 'number:0-'.description('价格'),
414
+ stock: 'integer:0-'.description('库存'),
415
+ category: 'string:2-50!',
416
+ tags: 'array<string>',
417
+ active: 'boolean'
418
+ });
419
+
420
+ // 订单 Schema
421
+ const orderSchema = dsl({
422
+ id: 'uuid!',
423
+ userId: 'uuid!',
424
+ items: 'array!1-100',
425
+ totalAmount: 'number:0-!',
426
+ status: 'pending|paid|shipped|delivered|cancelled',
427
+ createdAt: 'datetime!',
428
+ updatedAt: 'datetime'
429
+ });
430
+
431
+ // 导出所有 Schema
432
+ const schemas = { users: userSchema, products: productSchema, orders: orderSchema };
433
+ const mysqlExporter = new exporters.MySQLExporter();
434
+ const pgExporter = new exporters.PostgreSQLExporter({ schema: 'ecommerce' });
435
+
436
+ let mysqlDdl = '';
437
+ let pgDdl = '';
438
+
439
+ for (const [name, schema] of Object.entries(schemas)) {
440
+ mysqlDdl += mysqlExporter.export(name, schema) + '\n\n';
441
+ pgDdl += pgExporter.export(name, schema) + '\n\n';
442
+ }
443
+
444
+ fs.writeFileSync('schema.mysql.sql', mysqlDdl);
445
+ fs.writeFileSync('schema.pg.sql', pgDdl);
446
+
447
+ console.log('导出完成!');
448
+ ```
449
+
450
+ ---
451
+
452
+ ## 相关文档
453
+
454
+ - [MongoDB 导出器](mongodb-exporter.md)
455
+ - [MySQL 导出器](mysql-exporter.md)
456
+ - [PostgreSQL 导出器](postgresql-exporter.md)
457
+ - [TypeConverter](type-converter.md)
458
+ - [DSL 语法](dsl-syntax.md)
459
+