sqlseed 0.1.0__py3-none-any.whl

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 (42) hide show
  1. sqlseed/__init__.py +121 -0
  2. sqlseed/_utils/__init__.py +11 -0
  3. sqlseed/_utils/logger.py +30 -0
  4. sqlseed/_utils/metrics.py +45 -0
  5. sqlseed/_utils/progress.py +14 -0
  6. sqlseed/_utils/schema_helpers.py +51 -0
  7. sqlseed/_utils/sql_safe.py +45 -0
  8. sqlseed/_version.py +1 -0
  9. sqlseed/cli/__init__.py +3 -0
  10. sqlseed/cli/main.py +316 -0
  11. sqlseed/config/__init__.py +14 -0
  12. sqlseed/config/loader.py +66 -0
  13. sqlseed/config/models.py +99 -0
  14. sqlseed/config/snapshot.py +91 -0
  15. sqlseed/core/__init__.py +14 -0
  16. sqlseed/core/column_dag.py +108 -0
  17. sqlseed/core/constraints.py +116 -0
  18. sqlseed/core/expression.py +71 -0
  19. sqlseed/core/mapper.py +257 -0
  20. sqlseed/core/orchestrator.py +578 -0
  21. sqlseed/core/relation.py +124 -0
  22. sqlseed/core/result.py +23 -0
  23. sqlseed/core/schema.py +97 -0
  24. sqlseed/core/transform.py +27 -0
  25. sqlseed/database/__init__.py +14 -0
  26. sqlseed/database/_protocol.py +72 -0
  27. sqlseed/database/optimizer.py +96 -0
  28. sqlseed/database/raw_sqlite_adapter.py +197 -0
  29. sqlseed/database/sqlite_utils_adapter.py +183 -0
  30. sqlseed/generators/__init__.py +11 -0
  31. sqlseed/generators/_protocol.py +73 -0
  32. sqlseed/generators/base_provider.py +448 -0
  33. sqlseed/generators/faker_provider.py +157 -0
  34. sqlseed/generators/mimesis_provider.py +203 -0
  35. sqlseed/generators/registry.py +86 -0
  36. sqlseed/generators/stream.py +157 -0
  37. sqlseed/py.typed +0 -0
  38. sqlseed-0.1.0.dist-info/METADATA +934 -0
  39. sqlseed-0.1.0.dist-info/RECORD +42 -0
  40. sqlseed-0.1.0.dist-info/WHEEL +4 -0
  41. sqlseed-0.1.0.dist-info/entry_points.txt +6 -0
  42. sqlseed-0.1.0.dist-info/licenses/LICENSE +17 -0
@@ -0,0 +1,934 @@
1
+ Metadata-Version: 2.4
2
+ Name: sqlseed
3
+ Version: 0.1.0
4
+ Summary: Declarative SQLite test data generation toolkit
5
+ Project-URL: Homepage, https://github.com/sunbos/sqlseed
6
+ Project-URL: Documentation, https://github.com/sunbos/sqlseed#readme
7
+ Project-URL: Repository, https://github.com/sunbos/sqlseed
8
+ Project-URL: Issues, https://github.com/sunbos/sqlseed/issues
9
+ Author-email: SunBo <1443584939@qq.com>
10
+ License-Expression: AGPL-3.0-or-later
11
+ License-File: LICENSE
12
+ Keywords: data-generation,database,seed,sqlite,testing
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Database
22
+ Classifier: Topic :: Software Development :: Testing
23
+ Requires-Python: >=3.10
24
+ Requires-Dist: click>=8.0
25
+ Requires-Dist: pluggy>=1.3
26
+ Requires-Dist: pydantic>=2.0
27
+ Requires-Dist: pyyaml>=6.0
28
+ Requires-Dist: rich>=13.0
29
+ Requires-Dist: rstr>=3.2
30
+ Requires-Dist: simpleeval>=1.0
31
+ Requires-Dist: sqlite-utils>=3.36
32
+ Requires-Dist: structlog>=24.0
33
+ Requires-Dist: typing-extensions>=4.0
34
+ Provides-Extra: all
35
+ Requires-Dist: faker>=30.0; extra == 'all'
36
+ Requires-Dist: mimesis>=18.0; extra == 'all'
37
+ Provides-Extra: dev
38
+ Requires-Dist: mypy>=1.10; extra == 'dev'
39
+ Requires-Dist: pre-commit>=3.0; extra == 'dev'
40
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
41
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
42
+ Requires-Dist: pytest>=8.0; extra == 'dev'
43
+ Requires-Dist: ruff>=0.5; extra == 'dev'
44
+ Provides-Extra: docs
45
+ Requires-Dist: mkdocs-material>=9.0; extra == 'docs'
46
+ Requires-Dist: mkdocstrings[python]>=0.25; extra == 'docs'
47
+ Provides-Extra: faker
48
+ Requires-Dist: faker>=30.0; extra == 'faker'
49
+ Provides-Extra: mimesis
50
+ Requires-Dist: mimesis>=18.0; extra == 'mimesis'
51
+ Description-Content-Type: text/markdown
52
+
53
+ <div align="center">
54
+
55
+ # 🌱 sqlseed
56
+
57
+ ### 声明式 SQLite 测试数据生成工具包
58
+
59
+ **一行代码,十万行数据。零配置智能生成,AI 驱动精准调优。**
60
+
61
+ [![CI](https://github.com/sunbos/sqlseed/actions/workflows/ci.yml/badge.svg)](https://github.com/sunbos/sqlseed/actions)
62
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-3776ab.svg?logo=python&logoColor=white)](https://www.python.org/downloads/)
63
+ [![License: AGPL v3](https://img.shields.io/badge/License-AGPL%20v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)
64
+ [![Code style: ruff](https://img.shields.io/badge/code%20style-ruff-000000.svg)](https://github.com/astral-sh/ruff)
65
+ [![Type: mypy](https://img.shields.io/badge/type%20checker-mypy-blue.svg)](https://mypy-lang.org/)
66
+
67
+ </div>
68
+
69
+ ---
70
+
71
+ ```python
72
+ import sqlseed
73
+
74
+ # 就这一行。自动推断 Schema,自动选择策略,自动优化写入。
75
+ result = sqlseed.fill("test.db", table="users", count=100_000)
76
+ print(result)
77
+ # → GenerationResult(table=users, count=100000, elapsed=2.34s, speed=42735 rows/s)
78
+ ```
79
+
80
+ ---
81
+
82
+ ## 💡 为什么选择 sqlseed?
83
+
84
+ 在开发和测试流程中,我们经常需要为 SQLite 数据库填充大量真实感的测试数据。传统方式要么手写冗长的数据生成脚本,要么使用难以维护的 SQL fixtures。sqlseed 用一种全新的声明式方式解决了这个问题:
85
+
86
+ | 特性 | sqlseed | 手写脚本 | SQL Fixtures |
87
+ |:---|:---:|:---:|:---:|
88
+ | 零配置智能生成 | ✅ | ❌ | ❌ |
89
+ | 外键自动维护 | ✅ | 手动 | 手动 |
90
+ | 10 万行 + 数据 | ✅ 流式 | ⚠️ OOM | ❌ |
91
+ | 列语义推断 | ✅ 8 级策略 | ❌ | ❌ |
92
+ | 可重复生成 | ✅ seed | ⚠️ 手动 | ✅ |
93
+ | AI 智能调优 | ✅ LLM | ❌ | ❌ |
94
+ | 配置热重用 | ✅ YAML | ❌ | ❌ |
95
+
96
+ ## ✨ 核心特性
97
+
98
+ <table>
99
+ <tr>
100
+ <td width="50%">
101
+
102
+ **🚀 零配置智能生成**
103
+
104
+ 自动推断数据库 Schema,通过 8 级策略链为每列选择最佳生成器。列名是 `email`?生成邮箱。列名是 `*_at`?生成时间戳。完全不需要配置。
105
+
106
+ </td>
107
+ <td width="50%">
108
+
109
+ **🎯 声明式精确控制**
110
+
111
+ 通过 Python API 或 YAML/JSON 配置精确控制每一列的数据生成策略、约束条件和空值比率。
112
+
113
+ </td>
114
+ </tr>
115
+ <tr>
116
+ <td>
117
+
118
+ **🔗 外键自动排序**
119
+
120
+ 拓扑排序自动检测表依赖关系,SharedPool 跨表共享值池,零配置维持引用完整性。
121
+
122
+ </td>
123
+ <td>
124
+
125
+ **🌊 流式内存安全**
126
+
127
+ `DataStream` 通过 `Iterator[list[dict]]` 逐批 yield,100 万行数据内存占用与 1000 行相同。
128
+
129
+ </td>
130
+ </tr>
131
+ <tr>
132
+ <td>
133
+
134
+ **🧮 表达式引擎 & 约束求解**
135
+
136
+ 支持派生列计算(`CutCard4byte = sCardNo[-8:]`),唯一性约束回溯求解,超时保护防止死循环。
137
+
138
+ </td>
139
+ <td>
140
+
141
+ **🤖 AI 一等公民**
142
+
143
+ `sqlseed-ai` 插件通过 LLM 分析 Schema 语义,自动生成 YAML 配置建议,支持自纠正闭环。
144
+
145
+ </td>
146
+ </tr>
147
+ <tr>
148
+ <td>
149
+
150
+ **🧩 11 个 Hook 全生命周期**
151
+
152
+ 基于 pluggy 的插件架构,从 Provider 注册到批次插入,覆盖数据生成的每个环节。
153
+
154
+ </td>
155
+ <td>
156
+
157
+ **📊 三级 PRAGMA 优化**
158
+
159
+ 根据数据量智能切换 LIGHT / MODERATE / AGGRESSIVE 三种写入策略,最大化吞吐量。
160
+
161
+ </td>
162
+ </tr>
163
+ </table>
164
+
165
+ ---
166
+
167
+ ## 📦 安装
168
+
169
+ ### 基础安装
170
+
171
+ ```bash
172
+ pip install sqlseed
173
+ ```
174
+
175
+ ### 选择数据引擎
176
+
177
+ ```bash
178
+ # 推荐:Mimesis(高性能,本地化支持好)
179
+ pip install sqlseed[mimesis]
180
+
181
+ # 可选:Faker(生态丰富)
182
+ pip install sqlseed[faker]
183
+
184
+ # 全部安装
185
+ pip install sqlseed[all]
186
+ ```
187
+
188
+ ### 可选插件
189
+
190
+ ```bash
191
+ # AI 智能分析插件(LLM 驱动)
192
+ pip install -e "./plugins/sqlseed-ai"
193
+
194
+ # MCP 服务器(让 AI 助手直接操作 sqlseed)
195
+ pip install -e "./plugins/mcp-server-sqlseed"
196
+ ```
197
+
198
+ <details>
199
+ <summary><b>📋 开发环境完整安装</b></summary>
200
+
201
+ ```bash
202
+ git clone https://github.com/sunbos/sqlseed.git
203
+ cd sqlseed
204
+
205
+ # 安装核心 + 所有 Provider + 开发依赖
206
+ pip install -e ".[dev,all]"
207
+
208
+ # 可选插件
209
+ pip install -e "./plugins/sqlseed-ai"
210
+ pip install -e "./plugins/mcp-server-sqlseed"
211
+
212
+ # 验证安装
213
+ pytest
214
+ ruff check src/ tests/
215
+ mypy src/sqlseed/
216
+ ```
217
+
218
+ </details>
219
+
220
+ ---
221
+
222
+ ## 🚀 快速开始
223
+
224
+ ### 30 秒上手
225
+
226
+ 假设你有一个 SQLite 数据库 `app.db`,其中有一张 `users` 表:
227
+
228
+ ```sql
229
+ CREATE TABLE users (
230
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
231
+ name TEXT NOT NULL,
232
+ email TEXT,
233
+ age INTEGER,
234
+ phone TEXT,
235
+ created_at TEXT,
236
+ is_active INTEGER DEFAULT 1,
237
+ balance REAL
238
+ );
239
+ ```
240
+
241
+ 只需一行代码即可填充 1 万行高质量测试数据:
242
+
243
+ ```python
244
+ import sqlseed
245
+
246
+ result = sqlseed.fill("app.db", table="users", count=10_000)
247
+ print(result)
248
+ # → GenerationResult(table=users, count=10000, elapsed=0.52s, speed=19230 rows/s)
249
+ ```
250
+
251
+ sqlseed 会自动:
252
+ - ✅ 跳过 `id`(自增主键)
253
+ - ✅ 跳过 `is_active`(有默认值)
254
+ - ✅ `name` → 生成真实姓名
255
+ - ✅ `email` → 生成邮箱地址
256
+ - ✅ `age` → 生成 18~100 的整数
257
+ - ✅ `phone` → 生成电话号码
258
+ - ✅ `created_at` → 生成日期时间(匹配 `*_at` 模式)
259
+ - ✅ `balance` → 生成浮点数
260
+
261
+ **完全零配置,智能推断一切。**
262
+
263
+ ---
264
+
265
+ ## 📖 使用教程
266
+
267
+ ### 教程 1:Python API — 精确控制每一列
268
+
269
+ 当你需要对数据有更精细的控制时,可以通过 `columns` 参数声明每列的生成策略:
270
+
271
+ ```python
272
+ import sqlseed
273
+
274
+ result = sqlseed.fill(
275
+ "app.db",
276
+ table="users",
277
+ count=50_000,
278
+ columns={
279
+ # 简写:直接指定生成器名
280
+ "email": "email",
281
+ "phone": "phone",
282
+
283
+ # 完整配置:指定参数
284
+ "age": {"type": "integer", "min_value": 18, "max_value": 65},
285
+ "balance": {"type": "float", "min_value": 0.0, "max_value": 100000.0, "precision": 2},
286
+ "name": "name",
287
+
288
+ # 从候选列表中随机选择
289
+ "status": {"type": "choice", "choices": ["active", "inactive", "banned"]},
290
+ },
291
+ provider="mimesis", # 使用 Mimesis 引擎
292
+ locale="zh_CN", # 中文地区
293
+ seed=42, # 固定种子,确保结果可重复
294
+ clear_before=True, # 生成前清空表
295
+ )
296
+ print(result)
297
+ ```
298
+
299
+ #### 支持的生成器类型
300
+
301
+ | 生成器 | 说明 | 参数示例 |
302
+ |:---|:---|:---|
303
+ | `string` | 随机字符串 | `min_length`, `max_length`, `charset` |
304
+ | `integer` | 整数 | `min_value`, `max_value` |
305
+ | `float` | 浮点数 | `min_value`, `max_value`, `precision` |
306
+ | `boolean` | 布尔值 | — |
307
+ | `name` | 人名 | — |
308
+ | `first_name` | 名 | — |
309
+ | `last_name` | 姓 | — |
310
+ | `email` | 邮箱 | — |
311
+ | `phone` | 电话 | — |
312
+ | `address` | 地址 | — |
313
+ | `company` | 公司名 | — |
314
+ | `url` | URL | — |
315
+ | `ipv4` | IPv4 地址 | — |
316
+ | `uuid` | UUID | — |
317
+ | `date` | 日期 | `start_year`, `end_year` |
318
+ | `datetime` | 日期时间 | `start_year`, `end_year` |
319
+ | `timestamp` | Unix 时间戳 | — |
320
+ | `text` | 长文本 | `min_length`, `max_length` |
321
+ | `sentence` | 句子 | — |
322
+ | `password` | 密码 | `length` |
323
+ | `choice` | 从列表选择 | `choices` |
324
+ | `json` | JSON 字符串 | `schema` |
325
+ | `pattern` | 正则匹配 | `regex` |
326
+ | `bytes` | 二进制数据 | `length` |
327
+ | `foreign_key` | 外键引用 | `ref_table`, `ref_column`, `strategy` |
328
+ | `skip` | 跳过(使用默认值/NULL)| — |
329
+
330
+ ---
331
+
332
+ ### 教程 2:多表关联 — 自动维持外键完整性
333
+
334
+ 使用上下文管理器模式可以处理跨表数据依赖:
335
+
336
+ ```python
337
+ import sqlseed
338
+
339
+ with sqlseed.connect("app.db", provider="mimesis", locale="zh_CN") as db:
340
+ # 步骤 1:先填充父表
341
+ db.fill("users", count=10_000, seed=42)
342
+
343
+ # 步骤 2:填充子表 — sqlseed 自动检测外键约束,
344
+ # 从 users.id 中随机选取值填入 orders.user_id
345
+ db.fill("orders", count=50_000, columns={
346
+ "amount": {"type": "float", "min_value": 9.99, "max_value": 999.99, "precision": 2},
347
+ "quantity": {"type": "integer", "min_value": 1, "max_value": 20},
348
+ "status": {"type": "choice", "choices": ["pending", "paid", "shipped", "delivered"]},
349
+ })
350
+
351
+ # 步骤 3:查看生成报告
352
+ print(db.report())
353
+ # → Database: app.db
354
+ # → ==================================================
355
+ # → users: 10000 rows
356
+ # → orders: 50000 rows
357
+ ```
358
+
359
+ > **💡 提示**:如果两张表之间有同名列(如 `sUserNo`),即使没有声明外键约束,sqlseed 也会通过 **SharedPool 隐式关联机制**自动维持跨表一致性。
360
+
361
+ ---
362
+
363
+ ### 教程 3:YAML 配置文件驱动批量生成
364
+
365
+ 对于复杂的多表场景,推荐使用 YAML 配置文件:
366
+
367
+ **1. 生成配置模板**
368
+
369
+ ```bash
370
+ sqlseed init generate.yaml --db app.db
371
+ ```
372
+
373
+ **2. 编辑配置文件**
374
+
375
+ ```yaml
376
+ # generate.yaml
377
+ db_path: "app.db"
378
+ provider: mimesis
379
+ locale: zh_CN
380
+ optimize_pragma: true
381
+
382
+ tables:
383
+ - name: users
384
+ count: 100000
385
+ clear_before: true
386
+ seed: 42
387
+ columns:
388
+ - name: username
389
+ generator: name
390
+ - name: email
391
+ generator: email
392
+ - name: phone
393
+ generator: phone
394
+ - name: age
395
+ generator: integer
396
+ params:
397
+ min_value: 18
398
+ max_value: 65
399
+ - name: status
400
+ generator: choice
401
+ params:
402
+ choices: [0, 1, 2]
403
+ null_ratio: 0.05 # 5% 概率为 NULL
404
+
405
+ - name: orders
406
+ count: 500000
407
+ batch_size: 10000 # 每批 1 万行,优化内存
408
+ columns:
409
+ - name: user_id
410
+ generator: foreign_key
411
+ params:
412
+ ref_table: users
413
+ ref_column: id
414
+ strategy: random
415
+ - name: amount
416
+ generator: float
417
+ params:
418
+ min_value: 1.0
419
+ max_value: 9999.99
420
+ precision: 2
421
+ - name: created_at
422
+ generator: datetime
423
+ params:
424
+ start_year: 2024
425
+ ```
426
+
427
+ **3. 执行生成**
428
+
429
+ ```bash
430
+ sqlseed fill --config generate.yaml
431
+ ```
432
+
433
+ 或在 Python 中:
434
+
435
+ ```python
436
+ results = sqlseed.fill_from_config("generate.yaml")
437
+ for r in results:
438
+ print(r)
439
+ ```
440
+
441
+ ---
442
+
443
+ ### 教程 4:派生列与表达式引擎
444
+
445
+ sqlseed v2.0 引入了列依赖 DAG 和表达式引擎,支持从已有列计算派生列:
446
+
447
+ ```yaml
448
+ # 银行卡信息表场景
449
+ tables:
450
+ - name: card_info
451
+ count: 10000
452
+ columns:
453
+ - name: sCardNo
454
+ generator: pattern
455
+ params:
456
+ regex: "62[0-9]{17}" # 19 位银联卡号
457
+ constraints:
458
+ unique: true
459
+
460
+ - name: CutCard4byte
461
+ derive_from: sCardNo # 依赖 sCardNo
462
+ expression: "value[-8:]" # 取后 8 位
463
+ constraints:
464
+ unique: true
465
+
466
+ - name: CutCard3byte
467
+ derive_from: sCardNo
468
+ expression: "value[-6:]" # 取后 6 位
469
+
470
+ - name: sUserNo
471
+ generator: pattern
472
+ params:
473
+ regex: "U[0-9]{10}"
474
+ constraints:
475
+ unique: true
476
+ ```
477
+
478
+ **运作原理**:
479
+ 1. sqlseed 构建列依赖 DAG:`sCardNo → CutCard4byte, CutCard3byte`
480
+ 2. 拓扑排序确定生成顺序
481
+ 3. 先生成 `sCardNo`,再通过表达式 `value[-8:]` 计算 `CutCard4byte`
482
+ 4. 如果 `CutCard4byte` 的唯一性约束失败,回溯重新生成 `sCardNo`
483
+
484
+ #### 表达式引擎支持的函数
485
+
486
+ | 函数 | 用法 | 说明 |
487
+ |:---|:---|:---|
488
+ | `upper(s)` | `upper(value)` | 转大写 |
489
+ | `lower(s)` | `lower(value)` | 转小写 |
490
+ | `len(s)` | `len(value)` | 获取长度 |
491
+ | `substr(s, start, end)` | `substr(value, 0, 8)` | 子串 |
492
+ | `concat(*args)` | `concat("PRE_", value)` | 拼接 |
493
+ | `zfill(s, width)` | `zfill(value, 10)` | 零填充 |
494
+ | `lpad(s, width, char)` | `lpad(value, 8, "0")` | 左填充 |
495
+ | `rpad(s, width, char)` | `rpad(value, 8, "0")` | 右填充 |
496
+ | `replace(s, old, new)` | `replace(value, "-", "")` | 替换 |
497
+ | `strip(s)` | `strip(value)` | 去空白 |
498
+ | `int(s)` | `int(value)` | 转整数 |
499
+ | `str(s)` | `str(value)` | 转字符串 |
500
+ | 切片 | `value[-8:]` | Python 切片语法 |
501
+ | 数学 | `value * 2 + 1` | 基本数学运算 |
502
+
503
+ > ⚠️ **安全保护**:表达式引擎基于 `simpleeval`,具有 5 秒超时保护,不允许 `import`、`exec` 或文件 I/O 操作。
504
+
505
+ ---
506
+
507
+ ### 教程 5:Transform 脚本 — 极端业务逻辑
508
+
509
+ 对于无法用声明式配置表达的复杂业务逻辑,可以编写 Python 变换脚本:
510
+
511
+ **1. 编写 transform 脚本**
512
+
513
+ ```python
514
+ # transform_users.py
515
+ def transform_row(row, ctx):
516
+ """每一行生成后都会经过此函数处理。"""
517
+
518
+ # 根据年龄计算 VIP 等级
519
+ age = row.get("age", 0)
520
+ if age >= 60:
521
+ row["vip_level"] = 3
522
+ elif age >= 40:
523
+ row["vip_level"] = 2
524
+ else:
525
+ row["vip_level"] = 1
526
+
527
+ # 标准化手机号格式
528
+ phone = row.get("phone", "")
529
+ if phone and not phone.startswith("+86"):
530
+ row["phone"] = f"+86{phone}"
531
+
532
+ return row
533
+ ```
534
+
535
+ **2. 在 CLI 中使用**
536
+
537
+ ```bash
538
+ sqlseed fill app.db --table users --count 10000 --transform transform_users.py
539
+ ```
540
+
541
+ **3. 在 YAML 中使用**
542
+
543
+ ```yaml
544
+ tables:
545
+ - name: users
546
+ count: 10000
547
+ transform: "./transform_users.py"
548
+ ```
549
+
550
+ ---
551
+
552
+ ### 教程 6:预览与调试
553
+
554
+ 在大量生成数据前,先预览看看效果:
555
+
556
+ **Python API:**
557
+
558
+ ```python
559
+ rows = sqlseed.preview("app.db", table="users", count=5, seed=42)
560
+ for row in rows:
561
+ print(row)
562
+ # → {'name': '张伟', 'email': 'zhangwei@example.com', 'age': 32, ...}
563
+ # → {'name': '李娜', 'email': 'lina@test.org', 'age': 28, ...}
564
+ # → ...
565
+ ```
566
+
567
+ **CLI(Rich 表格输出):**
568
+
569
+ ```bash
570
+ sqlseed preview app.db --table users --count 5
571
+
572
+ # ┏━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━┓
573
+ # ┃ name ┃ email ┃ age ┃ created_at ┃
574
+ # ┡━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━╇━━━━━╇━━━━━━━━━━━━━━━━━━━━━┩
575
+ # │ 张伟 │ zhangwei@example.com│ 32 │ 2024-03-15 08:23:11 │
576
+ # │ ... │ ... │ ... │ ... │
577
+ # └─────────┴─────────────────────┴─────┴─────────────────────┘
578
+ ```
579
+
580
+ **查看列映射策略:**
581
+
582
+ ```bash
583
+ sqlseed inspect app.db --table users --show-mapping
584
+
585
+ # 查看 sqlseed 为每一列选择了什么生成策略
586
+ # ┏━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┓
587
+ # ┃ Column ┃ Type ┃ Nullable ┃ Generator ┃ Params ┃
588
+ # ┡━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━┩
589
+ # │ id │ INTEGER │ ✗ │ skip │ {} │
590
+ # │ name │ TEXT │ ✗ │ name │ {} │
591
+ # │ email │ TEXT │ ✓ │ email │ {} │
592
+ # │ age │ INTEGER │ ✓ │ integer │ {min: 18...} │
593
+ # │ ... │ ... │ ... │ ... │ ... │
594
+ # └────────────┴─────────┴──────────┴──────────────┴──────────────┘
595
+ ```
596
+
597
+ ---
598
+
599
+ ### 教程 7:快照与回放
600
+
601
+ 保存一次成功的生成配置,以后随时精确回放:
602
+
603
+ ```bash
604
+ # 生成并保存快照
605
+ sqlseed fill app.db --table users --count 10000 --seed 42 --snapshot
606
+ # → Snapshot saved: snapshots/2026-04-15_033000_users.yaml
607
+
608
+ # 任意时刻回放
609
+ sqlseed replay snapshots/2026-04-15_033000_users.yaml
610
+ # → GenerationResult(table=users, count=10000, elapsed=0.52s, speed=19230 rows/s)
611
+ ```
612
+
613
+ 适用场景:
614
+ - 🧪 CI/CD 中需要可重复的测试数据
615
+ - 📋 团队间共享一致的测试环境
616
+ - 🔄 开发时快速重建数据库状态
617
+
618
+ ---
619
+
620
+ ### 教程 8:AI 智能配置(sqlseed-ai 插件)
621
+
622
+ 让 LLM 分析你的数据库 Schema,自动生成最佳配置建议:
623
+
624
+ ```bash
625
+ # 安装 AI 插件
626
+ pip install -e "./plugins/sqlseed-ai"
627
+
628
+ # 设置 API Key
629
+ export SQLSEED_AI_API_KEY="your-api-key"
630
+ export SQLSEED_AI_BASE_URL="https://your-llm-api-endpoint"
631
+
632
+ # AI 分析并生成配置
633
+ sqlseed ai-suggest app.db --table card_info --output card_info.yaml
634
+
635
+ # 带自纠正的 AI 建议(默认 3 轮修正)
636
+ sqlseed ai-suggest app.db --table card_info --output card_info.yaml --verify
637
+
638
+ # 指定模型
639
+ sqlseed ai-suggest app.db --table card_info --output card_info.yaml --model gpt-4o
640
+
641
+ # 跳过缓存
642
+ sqlseed ai-suggest app.db --table card_info --output card_info.yaml --no-cache
643
+ ```
644
+
645
+ **AI 工作流程**:
646
+
647
+ ```
648
+ 1. 提取 Schema 上下文(列信息、索引、样本数据、外键、数据分布)
649
+ 2. 构建带 Few-shot 示例的 LLM Prompt
650
+ 3. LLM 返回 JSON 格式的列配置建议
651
+ 4. AiConfigRefiner 自动验证配置的正确性
652
+ 5. 若发现错误(未知生成器、类型不匹配等),自动向 LLM 发送修正请求
653
+ 6. 最多 3 轮自纠正,输出经过验证的 YAML 配置
654
+ ```
655
+
656
+ > **💡 环境变量**:支持 `SQLSEED_AI_API_KEY`、`SQLSEED_AI_BASE_URL`、`SQLSEED_AI_MODEL`。默认模型为 `qwen3-coder-plus`。
657
+
658
+ ---
659
+
660
+ ### 教程 9:MCP 服务器集成
661
+
662
+ 通过 [Model Context Protocol](https://modelcontextprotocol.io/) 让 AI 助手(Claude、Cursor 等)直接操作 sqlseed:
663
+
664
+ ```bash
665
+ # 安装 MCP 服务器
666
+ pip install -e "./plugins/mcp-server-sqlseed"
667
+
668
+ # 启动
669
+ python -m mcp_server_sqlseed
670
+ ```
671
+
672
+ **MCP 提供的能力**:
673
+
674
+ | 类型 | 名称 | 说明 |
675
+ |:---|:---|:---|
676
+ | 📖 Resource | `sqlseed://schema/{db_path}/{table_name}` | 获取表 Schema 的 JSON 表示 |
677
+ | 🔍 Tool | `sqlseed_inspect_schema` | 检查 Schema(列、外键、索引、样本数据、schema_hash) |
678
+ | 🤖 Tool | `sqlseed_generate_yaml` | AI 驱动的 YAML 配置生成(含自纠正) |
679
+ | ⚡ Tool | `sqlseed_execute_fill` | 执行数据生成(支持 YAML 配置字符串) |
680
+
681
+ 这意味着你可以在 AI 助手中说:
682
+
683
+ > "分析 `app.db` 中 `card_info` 表的结构,生成 YAML 配置,然后填充 5000 行数据。"
684
+
685
+ AI 助手会依次调用 `inspect_schema` → `generate_yaml` → `execute_fill`,无需你手动编写任何代码。
686
+
687
+ ---
688
+
689
+ ### 教程 10:自定义 Provider 插件
690
+
691
+ 你可以创建自己的数据生成 Provider:
692
+
693
+ ```python
694
+ # my_provider.py
695
+ from __future__ import annotations
696
+ from typing import Any
697
+
698
+ class MyCustomProvider:
699
+ """实现 DataProvider Protocol 即可。不需要继承任何基类。"""
700
+
701
+ def __init__(self) -> None:
702
+ self._locale: str = "en_US"
703
+
704
+ @property
705
+ def name(self) -> str:
706
+ return "my_custom"
707
+
708
+ def set_locale(self, locale: str) -> None:
709
+ self._locale = locale
710
+
711
+ def set_seed(self, seed: int) -> None:
712
+ ...
713
+
714
+ def generate_string(self, *, min_length: int = 1, max_length: int = 100, charset: str | None = None) -> str:
715
+ return "custom_string"
716
+
717
+ # ... 实现其余 generate_* 方法
718
+ # 完整 Protocol 参见:src/sqlseed/generators/_protocol.py
719
+ ```
720
+
721
+ **注册方式 1:通过 `pyproject.toml` entry-point(推荐)**
722
+
723
+ ```toml
724
+ [project.entry-points."sqlseed"]
725
+ my_custom = "my_provider:MyCustomProvider"
726
+ ```
727
+
728
+ **注册方式 2:通过插件 Hook**
729
+
730
+ ```python
731
+ from sqlseed.plugins.hookspecs import hookimpl
732
+
733
+ class MyPlugin:
734
+ @hookimpl
735
+ def sqlseed_register_providers(self, registry):
736
+ from my_provider import MyCustomProvider
737
+ registry.register(MyCustomProvider())
738
+ ```
739
+
740
+ ---
741
+
742
+ ## 🖥️ CLI 命令速查
743
+
744
+ ```bash
745
+ # ═══════════════════════════════════════
746
+ # 📋 数据生成
747
+ # ═══════════════════════════════════════
748
+
749
+ # 零配置填充
750
+ sqlseed fill app.db --table users --count 10000
751
+
752
+ # 完整参数
753
+ sqlseed fill app.db -t users -n 100000 \
754
+ --provider mimesis \
755
+ --locale zh_CN \
756
+ --seed 42 \
757
+ --batch-size 10000 \
758
+ --clear \
759
+ --snapshot
760
+
761
+ # YAML 配置驱动
762
+ sqlseed fill --config generate.yaml
763
+
764
+ # Transform 脚本
765
+ sqlseed fill app.db -t users -n 10000 --transform transform.py
766
+
767
+ # ═══════════════════════════════════════
768
+ # 🔍 查看与预览
769
+ # ═══════════════════════════════════════
770
+
771
+ # 预览数据(不写入)
772
+ sqlseed preview app.db --table users --count 5
773
+
774
+ # 查看所有表
775
+ sqlseed inspect app.db
776
+
777
+ # 查看列映射策略
778
+ sqlseed inspect app.db --table users --show-mapping
779
+
780
+ # ═══════════════════════════════════════
781
+ # 📸 快照与回放
782
+ # ═══════════════════════════════════════
783
+
784
+ # 生成配置模板
785
+ sqlseed init generate.yaml --db app.db
786
+
787
+ # 回放快照
788
+ sqlseed replay snapshots/2026-04-15_users.yaml
789
+
790
+ # ═══════════════════════════════════════
791
+ # 🤖 AI 功能
792
+ # ═══════════════════════════════════════
793
+
794
+ # AI 建议(需安装 sqlseed-ai)
795
+ sqlseed ai-suggest app.db -t users -o users.yaml
796
+ sqlseed ai-suggest app.db -t users -o users.yaml --model gpt-4o --verify
797
+ ```
798
+
799
+ ---
800
+
801
+ ## 🧠 8 级智能列映射
802
+
803
+ sqlseed 的核心亮点之一是 `ColumnMapper` 的 8 级策略链。每一列都会按以下优先级尝试匹配:
804
+
805
+ ```
806
+ Level 1 │ 用户配置 columns={"email": "email"} 最高优先级
807
+
808
+ Level 2 │ 自定义精确匹配 通过插件 Hook 注册的规则
809
+
810
+ Level 3 │ 内置精确匹配 67 条规则:email→email, phone→phone, age→integer...
811
+
812
+ Level 4 │ 自定义模式匹配 通过插件 Hook 注册的正则规则
813
+
814
+ Level 5 │ 内置模式匹配 25 条正则:*_at→datetime, *_id→foreign_key, is_*→boolean...
815
+
816
+ Level 6 │ 跳过 有默认值或可 NULL → skip
817
+
818
+ Level 7 │ 类型忠实回退 VARCHAR(32)→最长32字符, INT8→0~255, BLOB(1024)→1024字节
819
+
820
+ Level 8 │ 默认 string (min=5, max=50)
821
+ ```
822
+
823
+ 这意味着:
824
+
825
+ - 列名 `user_email` → Level 5 模式匹配 `*_email` → `email` 生成器 ✅
826
+ - 列名 `is_verified` → Level 5 模式匹配 `is_*` → `boolean` 生成器 ✅
827
+ - 列类型 `VARCHAR(20)` → Level 7 类型回退 → 最长 20 字符的字符串 ✅
828
+ - 列有 `DEFAULT 1` → Level 6 → 跳过生成 ✅
829
+
830
+ ---
831
+
832
+ ## 🧩 插件系统
833
+
834
+ sqlseed 通过 [pluggy](https://pluggy.readthedocs.io/) 提供 11 个 Hook 点,覆盖数据生成全生命周期:
835
+
836
+ | Hook | firstresult | 触发时机 |
837
+ |:---|:---:|:---|
838
+ | `sqlseed_register_providers` | | 注册自定义数据 Provider |
839
+ | `sqlseed_register_column_mappers` | | 注册自定义列映射规则 |
840
+ | `sqlseed_ai_analyze_table` | ✓ | AI 分析表 Schema(返回列配置建议) |
841
+ | `sqlseed_pre_generate_templates` | ✓ | AI 预计算候选值池 |
842
+ | `sqlseed_before_generate` | | 数据生成循环前 |
843
+ | `sqlseed_after_generate` | | 数据生成完成后 |
844
+ | `sqlseed_transform_row` | | 逐行变换(热路径,注意性能) |
845
+ | `sqlseed_transform_batch` | | 逐批变换(支持链式处理) |
846
+ | `sqlseed_before_insert` | | 每批写入 DB 前 |
847
+ | `sqlseed_after_insert` | | 每批写入 DB 后 |
848
+ | `sqlseed_shared_pool_loaded` | | 跨表共享池加载完成 |
849
+
850
+ ---
851
+
852
+ ## 🏗️ 项目架构
853
+
854
+ ```
855
+ src/sqlseed/
856
+ ├── __init__.py # 公共 API (fill, connect, fill_from_config, preview)
857
+ ├── core/ # ===== 核心编排层 =====
858
+ │ ├── orchestrator.py # DataOrchestrator 主引擎
859
+ │ ├── mapper.py # ColumnMapper 8 级策略链
860
+ │ ├── schema.py # SchemaInferrer — 推断列、索引、数据分布
861
+ │ ├── relation.py # RelationResolver + SharedPool — FK 与跨表共享
862
+ │ ├── column_dag.py # ColumnDAG — 列依赖图 + 拓扑排序
863
+ │ ├── expression.py # ExpressionEngine — 安全表达式 (simpleeval + 超时)
864
+ │ ├── constraints.py # ConstraintSolver — 唯一性回溯求解
865
+ │ ├── transform.py # TransformLoader — 用户脚本动态加载
866
+ │ └── result.py # GenerationResult 数据类
867
+ ├── generators/ # ===== 数据生成层 =====
868
+ │ ├── _protocol.py # DataProvider Protocol (24 个 generate_* 方法)
869
+ │ ├── registry.py # ProviderRegistry (entry-point 自动发现)
870
+ │ ├── base_provider.py # 内置基础生成器(零依赖)
871
+ │ ├── faker_provider.py # Faker 适配器
872
+ │ ├── mimesis_provider.py # Mimesis 适配器
873
+ │ └── stream.py # DataStream 流式生成 + 约束回溯
874
+ ├── database/ # ===== 数据库层 =====
875
+ │ ├── _protocol.py # DatabaseAdapter Protocol (ColumnInfo, ForeignKeyInfo, IndexInfo)
876
+ │ ├── sqlite_utils_adapter.py # 默认适配器
877
+ │ ├── raw_sqlite_adapter.py # sqlite3 回退适配器
878
+ │ └── optimizer.py # PragmaOptimizer 三级优化
879
+ ├── plugins/ # ===== 插件层 =====
880
+ │ ├── hookspecs.py # 11 个 pluggy Hook 定义
881
+ │ └── manager.py # PluginManager
882
+ ├── config/ # ===== 配置管理 =====
883
+ │ ├── models.py # Pydantic 模型 (GeneratorConfig/TableConfig/ColumnConfig)
884
+ │ ├── loader.py # YAML/JSON 加载与保存
885
+ │ └── snapshot.py # 快照保存与回放
886
+ ├── cli/ # ===== CLI =====
887
+ │ └── main.py # click 命令 (fill/preview/inspect/init/replay/ai-suggest)
888
+ └── _utils/ # ===== 内部工具 =====
889
+ ├── sql_safe.py # quote_identifier — SQL 注入防护
890
+ ├── schema_helpers.py # AUTOINCREMENT 检测
891
+ ├── metrics.py # MetricsCollector 性能度量
892
+ ├── progress.py # Rich 进度条
893
+ └── logger.py # structlog 日志
894
+
895
+ plugins/
896
+ ├── sqlseed-ai/ # AI 插件 — LLM 驱动的智能配置
897
+ │ └── src/sqlseed_ai/ # SchemaAnalyzer, AiConfigRefiner, Few-shot 示例...
898
+ └── mcp-server-sqlseed/ # MCP 服务器 — AI 助手交互
899
+ └── src/mcp_server_sqlseed/ # FastMCP 工具 (inspect/generate_yaml/execute_fill)
900
+ ```
901
+
902
+ ---
903
+
904
+ ## 🛠️ 开发
905
+
906
+ ```bash
907
+ # 运行测试(含覆盖率)
908
+ pytest
909
+
910
+ # 代码检查
911
+ ruff check src/ tests/
912
+
913
+ # 自动修复
914
+ ruff check --fix src/ tests/
915
+
916
+ # 类型检查
917
+ mypy src/sqlseed/
918
+ ```
919
+
920
+ 测试覆盖了所有核心模块,路径结构与 `src/` 一一对应:`test_core/`、`test_database/`、`test_generators/`、`test_plugins/`、`test_config/`、`test_utils/`。
921
+
922
+ ---
923
+
924
+ ## 📄 License
925
+
926
+ [AGPL-3.0-or-later](LICENSE)
927
+
928
+ ---
929
+
930
+ <div align="center">
931
+
932
+ **🌱 sqlseed** — *Stop writing fixtures. Start generating data.*
933
+
934
+ </div>