diagram-db 0.2.0__tar.gz
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.
- diagram_db-0.2.0/CHANGELOG.md +34 -0
- diagram_db-0.2.0/LICENSE +21 -0
- diagram_db-0.2.0/MANIFEST.in +10 -0
- diagram_db-0.2.0/PKG-INFO +277 -0
- diagram_db-0.2.0/README.md +245 -0
- diagram_db-0.2.0/examples/biblioteca.spec.md +36 -0
- diagram_db-0.2.0/examples/prestamos_taveras.spec.md +71 -0
- diagram_db-0.2.0/examples/tienda.spec.md +59 -0
- diagram_db-0.2.0/pyproject.toml +72 -0
- diagram_db-0.2.0/setup.cfg +4 -0
- diagram_db-0.2.0/src/diagram_db/__init__.py +29 -0
- diagram_db-0.2.0/src/diagram_db/__main__.py +8 -0
- diagram_db-0.2.0/src/diagram_db/cardinality.py +143 -0
- diagram_db-0.2.0/src/diagram_db/cli.py +235 -0
- diagram_db-0.2.0/src/diagram_db/diagnostics.py +40 -0
- diagram_db-0.2.0/src/diagram_db/model.py +79 -0
- diagram_db-0.2.0/src/diagram_db/parser.py +452 -0
- diagram_db-0.2.0/src/diagram_db/render.py +258 -0
- diagram_db-0.2.0/src/diagram_db/validate.py +206 -0
- diagram_db-0.2.0/src/diagram_db.egg-info/PKG-INFO +277 -0
- diagram_db-0.2.0/src/diagram_db.egg-info/SOURCES.txt +23 -0
- diagram_db-0.2.0/src/diagram_db.egg-info/dependency_links.txt +1 -0
- diagram_db-0.2.0/src/diagram_db.egg-info/entry_points.txt +2 -0
- diagram_db-0.2.0/src/diagram_db.egg-info/requires.txt +5 -0
- diagram_db-0.2.0/src/diagram_db.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Formato basado en [Keep a Changelog](https://keepachangelog.com/es-ES/1.1.0/).
|
|
4
|
+
El proyecto usa [versionado semántico](https://semver.org/lang/es/).
|
|
5
|
+
|
|
6
|
+
## [0.2.0] — 2026-10-29
|
|
7
|
+
|
|
8
|
+
Primera versión distribuible como paquete de Python.
|
|
9
|
+
|
|
10
|
+
### Añadido
|
|
11
|
+
|
|
12
|
+
- Paquete instalable con `pip install diagram-db` y el comando `diagram-db`.
|
|
13
|
+
- Landing pública en <https://jeironpro.github.io/diagram-db/> con un
|
|
14
|
+
playground que ejecuta el analizador real en el navegador.
|
|
15
|
+
- `import graphviz` deja de ser obligatorio: sin el paquete se pueden exportar
|
|
16
|
+
`--format dot` y `--format json`, y solo el render de imagen falla con un
|
|
17
|
+
mensaje claro.
|
|
18
|
+
- Publicación automática en PyPI al empujar un tag `v*`, con verificación
|
|
19
|
+
posterior de la versión publicada.
|
|
20
|
+
|
|
21
|
+
## [0.1.0] — 2026-10-21
|
|
22
|
+
|
|
23
|
+
### Añadido
|
|
24
|
+
|
|
25
|
+
- Lectura de specs markdown con entidades, campos y modificadores `PK`, `UK`,
|
|
26
|
+
`FK -> tabla.columna`, `not null` y `null`.
|
|
27
|
+
- Cardinalidades inferidas del FK y sección opcional `## Relaciones` con
|
|
28
|
+
atajos `1:1`, `1:N` y `N:M`.
|
|
29
|
+
- Validación con diagnósticos `E0xx` y avisos `W0xx`, código de salida por
|
|
30
|
+
severidad.
|
|
31
|
+
- Render SVG y PNG con Graphviz: tablas con insignias, pata de cuervo y
|
|
32
|
+
etiquetas con el campo y la cardinalidad.
|
|
33
|
+
- Export `--format dot` y `--format json`, `--rankdir`, `--check` y
|
|
34
|
+
`--allow-no-pk`.
|
diagram_db-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 jeironpro
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Archivos que entran al sdist; el wheel solo lleva el paquete y sus metadatos.
|
|
2
|
+
include LICENSE
|
|
3
|
+
include CHANGELOG.md
|
|
4
|
+
recursive-include examples *.md
|
|
5
|
+
|
|
6
|
+
# Fuera del sdist: tests, landing y configuración de CI
|
|
7
|
+
prune tests
|
|
8
|
+
prune landing
|
|
9
|
+
prune docs
|
|
10
|
+
prune .github
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: diagram-db
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Genera diagramas entidad-relación con pata de cuervo a partir de un spec.md
|
|
5
|
+
Author: jeironpro
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/jeironpro/diagram-db
|
|
8
|
+
Project-URL: Documentation, https://jeironpro.github.io/diagram-db/
|
|
9
|
+
Project-URL: Repository, https://github.com/jeironpro/diagram-db
|
|
10
|
+
Project-URL: Issues, https://github.com/jeironpro/diagram-db/issues
|
|
11
|
+
Project-URL: Changelog, https://github.com/jeironpro/diagram-db/blob/main/CHANGELOG.md
|
|
12
|
+
Keywords: diagram,entity-relationship,erd,graphviz,markdown,schema,sql
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Documentation
|
|
23
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: graphviz<1.0,>=0.21
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
30
|
+
Requires-Dist: ruff>=0.16; extra == "dev"
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
# diagram-db
|
|
34
|
+
|
|
35
|
+
Genera diagramas entidad-relación a partir de un `spec.md` en markdown.
|
|
36
|
+
|
|
37
|
+
Las entidades, sus campos y las claves PK/FK se declaran en el spec; la
|
|
38
|
+
herramienta valida el modelo (referencias, tipos, claves) y produce un diagrama
|
|
39
|
+
con pata de cuervo en SVG o PNG usando Graphviz. Sin base de datos, sin ORM y
|
|
40
|
+
sin servicios externos.
|
|
41
|
+
|
|
42
|
+
- Landing y [playground](https://jeironpro.github.io/diagram-db/) que ejecuta el
|
|
43
|
+
analizador real en el navegador.
|
|
44
|
+
- Paquete en [PyPI](https://pypi.org/project/diagram-db/).
|
|
45
|
+
|
|
46
|
+
## Requisitos
|
|
47
|
+
|
|
48
|
+
- Python 3.10 o superior.
|
|
49
|
+
- Graphviz con el binario `dot` (`dnf install graphviz` / `apt install graphviz`).
|
|
50
|
+
|
|
51
|
+
## Instalación
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install diagram-db
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Para trabajar sobre el código, con el entorno virtual del repo:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
python3 -m venv .venv
|
|
61
|
+
.venv/bin/pip install -r requirements.txt
|
|
62
|
+
.venv/bin/pip install -e .
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
En los dos casos queda disponible el comando `diagram-db` y también
|
|
66
|
+
`python -m diagram_db`. Si falta el paquete `graphviz`, los formatos `dot` y
|
|
67
|
+
`json` siguen funcionando; solo la generación de imágenes falla con un mensaje
|
|
68
|
+
claro.
|
|
69
|
+
|
|
70
|
+
## Uso
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
diagram-db examples/tienda.spec.md -o salida/
|
|
74
|
+
# escribe salida/tienda.svg
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
| Opción | Efecto |
|
|
78
|
+
|---|---|
|
|
79
|
+
| `-o, --output` | Directorio de salida, o archivo `.svg`/`.png` si se pide un solo formato |
|
|
80
|
+
| `--format` | `svg` (por defecto), `png`, `dot` o `json`; se combinan con comas |
|
|
81
|
+
| `--rankdir` | `TB` (por defecto), `LR`, `BT` o `RL` |
|
|
82
|
+
| `--check` | Solo valida el spec, sin escribir archivos |
|
|
83
|
+
| `--allow-no-pk` | Una entidad sin PK pasa de error a aviso |
|
|
84
|
+
| `--quiet` | Oculta avisos y mensajes de éxito |
|
|
85
|
+
|
|
86
|
+
Códigos de salida: `0` correcto, `1` errores en el spec, `2` error de uso.
|
|
87
|
+
|
|
88
|
+
## Formato del spec
|
|
89
|
+
|
|
90
|
+
```markdown
|
|
91
|
+
# Esquema: Tienda
|
|
92
|
+
|
|
93
|
+
## Entidades
|
|
94
|
+
|
|
95
|
+
### users
|
|
96
|
+
- id: int PK
|
|
97
|
+
- email: varchar(255) UK, not null
|
|
98
|
+
- manager_id: int FK -> users.id, null
|
|
99
|
+
|
|
100
|
+
### products
|
|
101
|
+
- id: int PK
|
|
102
|
+
- sku: varchar(40) UK, not null
|
|
103
|
+
- price: decimal(10,2), not null
|
|
104
|
+
|
|
105
|
+
### orders
|
|
106
|
+
- id: int PK
|
|
107
|
+
- user_id: int FK -> users.id, not null
|
|
108
|
+
- total: decimal(10,2), not null
|
|
109
|
+
|
|
110
|
+
### order_items
|
|
111
|
+
- order_id: int PK, FK -> orders.id
|
|
112
|
+
- product_id: int PK, FK -> products.id
|
|
113
|
+
- qty: int, not null
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Reglas:
|
|
117
|
+
|
|
118
|
+
- `## Entidades` es obligatoria; lo que haya antes se ignora y el `# Título` se
|
|
119
|
+
usa como título del diagrama.
|
|
120
|
+
- Cada entidad es un `### nombre`. Los nombres con punto (por ejemplo
|
|
121
|
+
`sales.order`) se encierran en comillas invertidas dentro del encabezado.
|
|
122
|
+
- Cada campo es `- nombre: tipo` seguido de modificadores opcionales, en
|
|
123
|
+
cualquier orden y separados por comas o espacios.
|
|
124
|
+
- Las comas dentro de paréntesis no separan modificadores: `decimal(10,2)` se
|
|
125
|
+
conserva como un solo tipo.
|
|
126
|
+
- Los bloques de código y los comentarios `<!-- ... -->` se ignoran.
|
|
127
|
+
- Un campo es anulable por defecto; una PK siempre es obligatoria.
|
|
128
|
+
|
|
129
|
+
### Modificadores
|
|
130
|
+
|
|
131
|
+
| Modificador | Alias | Efecto |
|
|
132
|
+
|---|---|---|
|
|
133
|
+
| `PK` | `pk` | Clave primaria; varias líneas forman una PK compuesta |
|
|
134
|
+
| `UK` | `uk`, `unique` | Clave única |
|
|
135
|
+
| `FK -> tabla.columna` | `fk` | Clave foránea; la columna es opcional si la PK destino es simple |
|
|
136
|
+
| `not null` | `nn` | Campo obligatorio |
|
|
137
|
+
| `null` | `nullable` | Fuerza la nulabilidad |
|
|
138
|
+
|
|
139
|
+
### Cardinalidades
|
|
140
|
+
|
|
141
|
+
Se infieren del propio FK: si el campo es anulable el padre es opcional, y si
|
|
142
|
+
es `UK` la relación es 1:1. Una entidad cuya PK se compone solo de FK se dibuja
|
|
143
|
+
como tabla puente y sus aristas se etiquetan `N:M`.
|
|
144
|
+
|
|
145
|
+
Para sobrescribir una arista concreta, usa la sección opcional `## Relaciones`:
|
|
146
|
+
|
|
147
|
+
```markdown
|
|
148
|
+
## Relaciones
|
|
149
|
+
|
|
150
|
+
- users.manager_id: 0..1:N "reporta a"
|
|
151
|
+
- orders.user_id: 1:N "realiza"
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
- `1:1`, `1:N` y `N:M` son atajos; la forma explícita es `<padre>:<hijo>`, con
|
|
155
|
+
`1` o `0..1` en el padre y `1`, `0..1`, `N`, `0..N` o `1..N` en el hijo.
|
|
156
|
+
- El texto entre comillas reemplaza el nombre del campo en la etiqueta; la
|
|
157
|
+
cardinalidad se sigue mostrando (`reporta a 0..1:N`).
|
|
158
|
+
|
|
159
|
+
## Cómo leer el diagrama
|
|
160
|
+
|
|
161
|
+
- Cabecera con el nombre de la entidad y un filete terracota debajo; el
|
|
162
|
+
filete se vuelve rojizo si la entidad no declara PK.
|
|
163
|
+
- Insignias por columna: `PK`, `FK`, `UK`, combinables.
|
|
164
|
+
- `?` al final del tipo indica que el campo es anulable.
|
|
165
|
+
- Cada arista va del padre al hijo con el nombre del campo y su cardinalidad
|
|
166
|
+
al lado del punto medio, sin tapar la línea; las puntas terminan en el borde
|
|
167
|
+
de la tabla.
|
|
168
|
+
- Marcadores: `teetee` (doble barra) = exactamente uno, `odottee` (círculo y
|
|
169
|
+
barra) = cero o uno, `crow` = cero o muchos, `crowtee` = uno o muchos.
|
|
170
|
+
|
|
171
|
+
## Diagnósticos
|
|
172
|
+
|
|
173
|
+
Cada problema se informa como `archivo:línea: CÓDIGO mensaje` por stderr. Los
|
|
174
|
+
errores impiden generar el diagrama; los avisos no.
|
|
175
|
+
|
|
176
|
+
| Código | Tipo | Cuándo aparece |
|
|
177
|
+
|---|---|---|
|
|
178
|
+
| E000 | error | Falta `## Entidades` |
|
|
179
|
+
| E001 | error | Entidad duplicada |
|
|
180
|
+
| E002 | error | Campo duplicado en la misma entidad |
|
|
181
|
+
| E003 | error | Entidad sin campos |
|
|
182
|
+
| E004 | error | FK a una entidad inexistente |
|
|
183
|
+
| E005 | error | FK a una columna inexistente |
|
|
184
|
+
| E006 | error | FK sin columna y la PK destino no es simple |
|
|
185
|
+
| E007 | error | Entidad sin PK |
|
|
186
|
+
| E008 | error | Línea no reconocida dentro de `## Entidades` |
|
|
187
|
+
| E009 | error | Nombre de entidad no válido |
|
|
188
|
+
| E010 | error | Nombre de campo no válido |
|
|
189
|
+
| E011 | error | Línea de campo sin `:` |
|
|
190
|
+
| E012 | error | Campo sin tipo |
|
|
191
|
+
| E013 | error | Modificador no reconocido |
|
|
192
|
+
| E020 | error | Línea de `## Relaciones` mal formada |
|
|
193
|
+
| E021 | error | La relación apunta a una entidad o campo inexistente |
|
|
194
|
+
| E022 | error | La relación apunta a un campo que no es FK |
|
|
195
|
+
| E023 | error | Cardinalidad no válida |
|
|
196
|
+
| E024 | error | Relación duplicada para el mismo FK |
|
|
197
|
+
| W001 | aviso | FK a una columna que no es PK ni UK |
|
|
198
|
+
| W002 | aviso | Tipo del FK distinto del tipo destino |
|
|
199
|
+
| W003 | aviso | Campo `PK` declarado como `null` (gana `PK`) |
|
|
200
|
+
| W004 | aviso | Entidad sin PK con `--allow-no-pk` |
|
|
201
|
+
|
|
202
|
+
## Landing y playground
|
|
203
|
+
|
|
204
|
+
La web vive en [`landing/`](landing/index.html) y se publica en GitHub Pages. Es
|
|
205
|
+
HTML, CSS y JavaScript sin compilación; el playground descarga Pyodide solo
|
|
206
|
+
cuando se pide el primer análisis y ejecuta el mismo paquete que instala `pip`,
|
|
207
|
+
servido desde `landing/vendor/diagram_db`.
|
|
208
|
+
|
|
209
|
+
La publicación es un paso manual de una sola vez: activar Pages en
|
|
210
|
+
**Settings → Pages → Source: GitHub Actions** y definir la variable de
|
|
211
|
+
repositorio `PAGES_ENABLED=true`. Hasta entonces el workflow queda omitido, así
|
|
212
|
+
que `main` no falla mientras no esté activado.
|
|
213
|
+
|
|
214
|
+
Esa copia es la fuente única del playground y CI falla si diverge. Tras tocar
|
|
215
|
+
`src/diagram_db`, sincronízala:
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
cp src/diagram_db/*.py landing/vendor/diagram_db/
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Para verla en local basta servir la carpeta:
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
python3 -m http.server 8765 --directory landing
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Desarrollo
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
.venv/bin/pip install -r test-requirements.txt
|
|
231
|
+
ruff check .
|
|
232
|
+
ruff format --check .
|
|
233
|
+
pre-commit run --all-files
|
|
234
|
+
.venv/bin/python -m pytest
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Las dependencias se gestionan con `pip-tools` a partir de `pyproject.toml`:
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
pip-compile pyproject.toml -o requirements.txt
|
|
241
|
+
pip-compile --extra dev pyproject.toml -o test-requirements.txt
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
CI (`.github/workflows/ci.yml`) corre Ruff, comprueba que la copia del playground
|
|
245
|
+
no diverja, pasa pytest en Python 3.10–3.13, construye el sdist y el wheel,
|
|
246
|
+
valida los metadatos con `twine check --strict` y prueba el wheel instalado en un
|
|
247
|
+
entorno limpio.
|
|
248
|
+
|
|
249
|
+
El release sale por tag `v*`: `.github/workflows/release.yml` corre los tests,
|
|
250
|
+
crea el GitHub Release con los artefactos, publica en PyPI con trusted
|
|
251
|
+
publishing (OIDC, sin tokens) y verifica que la versión instalada genera un
|
|
252
|
+
diagrama.
|
|
253
|
+
|
|
254
|
+
La landing se publica con `.github/workflows/pages.yml`, que queda omitido hasta
|
|
255
|
+
que Pages esté activado en el repositorio y la variable `PAGES_ENABLED` valga
|
|
256
|
+
`true`.
|
|
257
|
+
|
|
258
|
+
## Publicación
|
|
259
|
+
|
|
260
|
+
La versión vive en `diagram_db.__version__` y `pyproject.toml` la lee de ahí, así
|
|
261
|
+
que un release es un tag:
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
git tag v0.2.0 && git push origin v0.2.0
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
El workflow de release corre los tests, crea el GitHub Release con los
|
|
268
|
+
artefactos, publica en PyPI con trusted publishing (OIDC, sin tokens) y verifica
|
|
269
|
+
que `pip install diagram-db==<versión>` genera un diagrama. El publisher se
|
|
270
|
+
configura una sola vez en <https://pypi.org/manage/account/publishing/> con el
|
|
271
|
+
repositorio `jeironpro/diagram-db`, el workflow `release.yml` y el entorno
|
|
272
|
+
`pypi`.
|
|
273
|
+
|
|
274
|
+
## Licencia
|
|
275
|
+
|
|
276
|
+
Este proyecto está bajo la licencia **MIT**. Consulta el archivo
|
|
277
|
+
[LICENSE](LICENSE) para más detalles.
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# diagram-db
|
|
2
|
+
|
|
3
|
+
Genera diagramas entidad-relación a partir de un `spec.md` en markdown.
|
|
4
|
+
|
|
5
|
+
Las entidades, sus campos y las claves PK/FK se declaran en el spec; la
|
|
6
|
+
herramienta valida el modelo (referencias, tipos, claves) y produce un diagrama
|
|
7
|
+
con pata de cuervo en SVG o PNG usando Graphviz. Sin base de datos, sin ORM y
|
|
8
|
+
sin servicios externos.
|
|
9
|
+
|
|
10
|
+
- Landing y [playground](https://jeironpro.github.io/diagram-db/) que ejecuta el
|
|
11
|
+
analizador real en el navegador.
|
|
12
|
+
- Paquete en [PyPI](https://pypi.org/project/diagram-db/).
|
|
13
|
+
|
|
14
|
+
## Requisitos
|
|
15
|
+
|
|
16
|
+
- Python 3.10 o superior.
|
|
17
|
+
- Graphviz con el binario `dot` (`dnf install graphviz` / `apt install graphviz`).
|
|
18
|
+
|
|
19
|
+
## Instalación
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install diagram-db
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Para trabajar sobre el código, con el entorno virtual del repo:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
python3 -m venv .venv
|
|
29
|
+
.venv/bin/pip install -r requirements.txt
|
|
30
|
+
.venv/bin/pip install -e .
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
En los dos casos queda disponible el comando `diagram-db` y también
|
|
34
|
+
`python -m diagram_db`. Si falta el paquete `graphviz`, los formatos `dot` y
|
|
35
|
+
`json` siguen funcionando; solo la generación de imágenes falla con un mensaje
|
|
36
|
+
claro.
|
|
37
|
+
|
|
38
|
+
## Uso
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
diagram-db examples/tienda.spec.md -o salida/
|
|
42
|
+
# escribe salida/tienda.svg
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
| Opción | Efecto |
|
|
46
|
+
|---|---|
|
|
47
|
+
| `-o, --output` | Directorio de salida, o archivo `.svg`/`.png` si se pide un solo formato |
|
|
48
|
+
| `--format` | `svg` (por defecto), `png`, `dot` o `json`; se combinan con comas |
|
|
49
|
+
| `--rankdir` | `TB` (por defecto), `LR`, `BT` o `RL` |
|
|
50
|
+
| `--check` | Solo valida el spec, sin escribir archivos |
|
|
51
|
+
| `--allow-no-pk` | Una entidad sin PK pasa de error a aviso |
|
|
52
|
+
| `--quiet` | Oculta avisos y mensajes de éxito |
|
|
53
|
+
|
|
54
|
+
Códigos de salida: `0` correcto, `1` errores en el spec, `2` error de uso.
|
|
55
|
+
|
|
56
|
+
## Formato del spec
|
|
57
|
+
|
|
58
|
+
```markdown
|
|
59
|
+
# Esquema: Tienda
|
|
60
|
+
|
|
61
|
+
## Entidades
|
|
62
|
+
|
|
63
|
+
### users
|
|
64
|
+
- id: int PK
|
|
65
|
+
- email: varchar(255) UK, not null
|
|
66
|
+
- manager_id: int FK -> users.id, null
|
|
67
|
+
|
|
68
|
+
### products
|
|
69
|
+
- id: int PK
|
|
70
|
+
- sku: varchar(40) UK, not null
|
|
71
|
+
- price: decimal(10,2), not null
|
|
72
|
+
|
|
73
|
+
### orders
|
|
74
|
+
- id: int PK
|
|
75
|
+
- user_id: int FK -> users.id, not null
|
|
76
|
+
- total: decimal(10,2), not null
|
|
77
|
+
|
|
78
|
+
### order_items
|
|
79
|
+
- order_id: int PK, FK -> orders.id
|
|
80
|
+
- product_id: int PK, FK -> products.id
|
|
81
|
+
- qty: int, not null
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Reglas:
|
|
85
|
+
|
|
86
|
+
- `## Entidades` es obligatoria; lo que haya antes se ignora y el `# Título` se
|
|
87
|
+
usa como título del diagrama.
|
|
88
|
+
- Cada entidad es un `### nombre`. Los nombres con punto (por ejemplo
|
|
89
|
+
`sales.order`) se encierran en comillas invertidas dentro del encabezado.
|
|
90
|
+
- Cada campo es `- nombre: tipo` seguido de modificadores opcionales, en
|
|
91
|
+
cualquier orden y separados por comas o espacios.
|
|
92
|
+
- Las comas dentro de paréntesis no separan modificadores: `decimal(10,2)` se
|
|
93
|
+
conserva como un solo tipo.
|
|
94
|
+
- Los bloques de código y los comentarios `<!-- ... -->` se ignoran.
|
|
95
|
+
- Un campo es anulable por defecto; una PK siempre es obligatoria.
|
|
96
|
+
|
|
97
|
+
### Modificadores
|
|
98
|
+
|
|
99
|
+
| Modificador | Alias | Efecto |
|
|
100
|
+
|---|---|---|
|
|
101
|
+
| `PK` | `pk` | Clave primaria; varias líneas forman una PK compuesta |
|
|
102
|
+
| `UK` | `uk`, `unique` | Clave única |
|
|
103
|
+
| `FK -> tabla.columna` | `fk` | Clave foránea; la columna es opcional si la PK destino es simple |
|
|
104
|
+
| `not null` | `nn` | Campo obligatorio |
|
|
105
|
+
| `null` | `nullable` | Fuerza la nulabilidad |
|
|
106
|
+
|
|
107
|
+
### Cardinalidades
|
|
108
|
+
|
|
109
|
+
Se infieren del propio FK: si el campo es anulable el padre es opcional, y si
|
|
110
|
+
es `UK` la relación es 1:1. Una entidad cuya PK se compone solo de FK se dibuja
|
|
111
|
+
como tabla puente y sus aristas se etiquetan `N:M`.
|
|
112
|
+
|
|
113
|
+
Para sobrescribir una arista concreta, usa la sección opcional `## Relaciones`:
|
|
114
|
+
|
|
115
|
+
```markdown
|
|
116
|
+
## Relaciones
|
|
117
|
+
|
|
118
|
+
- users.manager_id: 0..1:N "reporta a"
|
|
119
|
+
- orders.user_id: 1:N "realiza"
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
- `1:1`, `1:N` y `N:M` son atajos; la forma explícita es `<padre>:<hijo>`, con
|
|
123
|
+
`1` o `0..1` en el padre y `1`, `0..1`, `N`, `0..N` o `1..N` en el hijo.
|
|
124
|
+
- El texto entre comillas reemplaza el nombre del campo en la etiqueta; la
|
|
125
|
+
cardinalidad se sigue mostrando (`reporta a 0..1:N`).
|
|
126
|
+
|
|
127
|
+
## Cómo leer el diagrama
|
|
128
|
+
|
|
129
|
+
- Cabecera con el nombre de la entidad y un filete terracota debajo; el
|
|
130
|
+
filete se vuelve rojizo si la entidad no declara PK.
|
|
131
|
+
- Insignias por columna: `PK`, `FK`, `UK`, combinables.
|
|
132
|
+
- `?` al final del tipo indica que el campo es anulable.
|
|
133
|
+
- Cada arista va del padre al hijo con el nombre del campo y su cardinalidad
|
|
134
|
+
al lado del punto medio, sin tapar la línea; las puntas terminan en el borde
|
|
135
|
+
de la tabla.
|
|
136
|
+
- Marcadores: `teetee` (doble barra) = exactamente uno, `odottee` (círculo y
|
|
137
|
+
barra) = cero o uno, `crow` = cero o muchos, `crowtee` = uno o muchos.
|
|
138
|
+
|
|
139
|
+
## Diagnósticos
|
|
140
|
+
|
|
141
|
+
Cada problema se informa como `archivo:línea: CÓDIGO mensaje` por stderr. Los
|
|
142
|
+
errores impiden generar el diagrama; los avisos no.
|
|
143
|
+
|
|
144
|
+
| Código | Tipo | Cuándo aparece |
|
|
145
|
+
|---|---|---|
|
|
146
|
+
| E000 | error | Falta `## Entidades` |
|
|
147
|
+
| E001 | error | Entidad duplicada |
|
|
148
|
+
| E002 | error | Campo duplicado en la misma entidad |
|
|
149
|
+
| E003 | error | Entidad sin campos |
|
|
150
|
+
| E004 | error | FK a una entidad inexistente |
|
|
151
|
+
| E005 | error | FK a una columna inexistente |
|
|
152
|
+
| E006 | error | FK sin columna y la PK destino no es simple |
|
|
153
|
+
| E007 | error | Entidad sin PK |
|
|
154
|
+
| E008 | error | Línea no reconocida dentro de `## Entidades` |
|
|
155
|
+
| E009 | error | Nombre de entidad no válido |
|
|
156
|
+
| E010 | error | Nombre de campo no válido |
|
|
157
|
+
| E011 | error | Línea de campo sin `:` |
|
|
158
|
+
| E012 | error | Campo sin tipo |
|
|
159
|
+
| E013 | error | Modificador no reconocido |
|
|
160
|
+
| E020 | error | Línea de `## Relaciones` mal formada |
|
|
161
|
+
| E021 | error | La relación apunta a una entidad o campo inexistente |
|
|
162
|
+
| E022 | error | La relación apunta a un campo que no es FK |
|
|
163
|
+
| E023 | error | Cardinalidad no válida |
|
|
164
|
+
| E024 | error | Relación duplicada para el mismo FK |
|
|
165
|
+
| W001 | aviso | FK a una columna que no es PK ni UK |
|
|
166
|
+
| W002 | aviso | Tipo del FK distinto del tipo destino |
|
|
167
|
+
| W003 | aviso | Campo `PK` declarado como `null` (gana `PK`) |
|
|
168
|
+
| W004 | aviso | Entidad sin PK con `--allow-no-pk` |
|
|
169
|
+
|
|
170
|
+
## Landing y playground
|
|
171
|
+
|
|
172
|
+
La web vive en [`landing/`](landing/index.html) y se publica en GitHub Pages. Es
|
|
173
|
+
HTML, CSS y JavaScript sin compilación; el playground descarga Pyodide solo
|
|
174
|
+
cuando se pide el primer análisis y ejecuta el mismo paquete que instala `pip`,
|
|
175
|
+
servido desde `landing/vendor/diagram_db`.
|
|
176
|
+
|
|
177
|
+
La publicación es un paso manual de una sola vez: activar Pages en
|
|
178
|
+
**Settings → Pages → Source: GitHub Actions** y definir la variable de
|
|
179
|
+
repositorio `PAGES_ENABLED=true`. Hasta entonces el workflow queda omitido, así
|
|
180
|
+
que `main` no falla mientras no esté activado.
|
|
181
|
+
|
|
182
|
+
Esa copia es la fuente única del playground y CI falla si diverge. Tras tocar
|
|
183
|
+
`src/diagram_db`, sincronízala:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
cp src/diagram_db/*.py landing/vendor/diagram_db/
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Para verla en local basta servir la carpeta:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
python3 -m http.server 8765 --directory landing
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Desarrollo
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
.venv/bin/pip install -r test-requirements.txt
|
|
199
|
+
ruff check .
|
|
200
|
+
ruff format --check .
|
|
201
|
+
pre-commit run --all-files
|
|
202
|
+
.venv/bin/python -m pytest
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Las dependencias se gestionan con `pip-tools` a partir de `pyproject.toml`:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
pip-compile pyproject.toml -o requirements.txt
|
|
209
|
+
pip-compile --extra dev pyproject.toml -o test-requirements.txt
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
CI (`.github/workflows/ci.yml`) corre Ruff, comprueba que la copia del playground
|
|
213
|
+
no diverja, pasa pytest en Python 3.10–3.13, construye el sdist y el wheel,
|
|
214
|
+
valida los metadatos con `twine check --strict` y prueba el wheel instalado en un
|
|
215
|
+
entorno limpio.
|
|
216
|
+
|
|
217
|
+
El release sale por tag `v*`: `.github/workflows/release.yml` corre los tests,
|
|
218
|
+
crea el GitHub Release con los artefactos, publica en PyPI con trusted
|
|
219
|
+
publishing (OIDC, sin tokens) y verifica que la versión instalada genera un
|
|
220
|
+
diagrama.
|
|
221
|
+
|
|
222
|
+
La landing se publica con `.github/workflows/pages.yml`, que queda omitido hasta
|
|
223
|
+
que Pages esté activado en el repositorio y la variable `PAGES_ENABLED` valga
|
|
224
|
+
`true`.
|
|
225
|
+
|
|
226
|
+
## Publicación
|
|
227
|
+
|
|
228
|
+
La versión vive en `diagram_db.__version__` y `pyproject.toml` la lee de ahí, así
|
|
229
|
+
que un release es un tag:
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
git tag v0.2.0 && git push origin v0.2.0
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
El workflow de release corre los tests, crea el GitHub Release con los
|
|
236
|
+
artefactos, publica en PyPI con trusted publishing (OIDC, sin tokens) y verifica
|
|
237
|
+
que `pip install diagram-db==<versión>` genera un diagrama. El publisher se
|
|
238
|
+
configura una sola vez en <https://pypi.org/manage/account/publishing/> con el
|
|
239
|
+
repositorio `jeironpro/diagram-db`, el workflow `release.yml` y el entorno
|
|
240
|
+
`pypi`.
|
|
241
|
+
|
|
242
|
+
## Licencia
|
|
243
|
+
|
|
244
|
+
Este proyecto está bajo la licencia **MIT**. Consulta el archivo
|
|
245
|
+
[LICENSE](LICENSE) para más detalles.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Esquema: Biblioteca
|
|
2
|
+
|
|
3
|
+
Catálogo mínimo: quién escribe, qué se presta y quién lo recibe.
|
|
4
|
+
|
|
5
|
+
## Entidades
|
|
6
|
+
|
|
7
|
+
### autores
|
|
8
|
+
- id: int PK
|
|
9
|
+
- nombre: varchar(120), not null
|
|
10
|
+
- pais: varchar(60)
|
|
11
|
+
|
|
12
|
+
### libros
|
|
13
|
+
- id: int PK
|
|
14
|
+
- autor_id: int FK -> autores.id, not null
|
|
15
|
+
- titulo: varchar(200), not null
|
|
16
|
+
- isbn: varchar(20) UK, not null
|
|
17
|
+
- anio: int, not null
|
|
18
|
+
|
|
19
|
+
### socios
|
|
20
|
+
- id: int PK
|
|
21
|
+
- nombre: varchar(120), not null
|
|
22
|
+
- correo: varchar(150) UK, not null
|
|
23
|
+
- alta: date, not null
|
|
24
|
+
|
|
25
|
+
### prestamos
|
|
26
|
+
- id: int PK
|
|
27
|
+
- libro_id: int FK -> libros.id, not null
|
|
28
|
+
- socio_id: int FK -> socios.id, not null
|
|
29
|
+
- retirado: date, not null
|
|
30
|
+
- devuelto: date
|
|
31
|
+
|
|
32
|
+
## Relaciones
|
|
33
|
+
|
|
34
|
+
- libros.autor_id: 1:N "escribe"
|
|
35
|
+
- prestamos.libro_id: 1:N "presta"
|
|
36
|
+
- prestamos.socio_id: 1:N "recibe"
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Esquema: Préstamos Taveras
|
|
2
|
+
|
|
3
|
+
Sistema de préstamos semanales. Lo que está fuera de `## Entidades` no se
|
|
4
|
+
interpreta: sirve para documentar decisiones del modelo.
|
|
5
|
+
|
|
6
|
+
Convenciones:
|
|
7
|
+
|
|
8
|
+
- `uuid` es un hash SHA-256 en hexadecimal (64 caracteres) y actúa como clave
|
|
9
|
+
pública de cada tabla; `id` es la clave primaria interna.
|
|
10
|
+
- `pagos.empleado_id` referencia a un usuario con rol EMPLEADO. El diagrama no
|
|
11
|
+
puede expresar ese filtro: la columna guarda el id, no el rol.
|
|
12
|
+
|
|
13
|
+
## Entidades
|
|
14
|
+
|
|
15
|
+
### usuarios
|
|
16
|
+
- id: int PK
|
|
17
|
+
- uuid: char(64) UK, not null
|
|
18
|
+
- rol: enum(ADMIN, CLIENTE, EMPLEADO), not null
|
|
19
|
+
- nombre: varchar(100), not null
|
|
20
|
+
- apellidos: varchar(100), not null
|
|
21
|
+
- cedula: varchar(20) UK, not null
|
|
22
|
+
- correo: varchar(150) UK, not null
|
|
23
|
+
- contrasena: varchar(255), not null
|
|
24
|
+
- telefono: varchar(20)
|
|
25
|
+
- direccion: varchar(200)
|
|
26
|
+
|
|
27
|
+
### prestamos
|
|
28
|
+
- id: int PK
|
|
29
|
+
- uuid: char(64) UK, not null
|
|
30
|
+
- usuario_id: int FK -> usuarios.id, not null
|
|
31
|
+
- monto: decimal(12,2), not null
|
|
32
|
+
- monto_cuota: decimal(12,2), not null
|
|
33
|
+
- monto_mora: decimal(12,2), not null
|
|
34
|
+
- cantidad_semanas: int, not null
|
|
35
|
+
- dia_pago: enum(LUNES, MARTES, MIERCOLES, JUEVES, VIERNES, SABADO, DOMINGO), not null
|
|
36
|
+
|
|
37
|
+
### semanas_prestamo
|
|
38
|
+
- id: int PK
|
|
39
|
+
- uuid: char(64) UK, not null
|
|
40
|
+
- prestamo_id: int FK -> prestamos.id, not null
|
|
41
|
+
- numero_semana: int, not null
|
|
42
|
+
- monto: decimal(12,2), not null
|
|
43
|
+
- estado: enum(PAGADA, PENDIENTE, CANCELADA), not null
|
|
44
|
+
- fecha: date, not null
|
|
45
|
+
|
|
46
|
+
### pagos
|
|
47
|
+
- id: int PK
|
|
48
|
+
- uuid: char(64) UK, not null
|
|
49
|
+
- semanas_prestamo_id: int FK -> semanas_prestamo.id, not null
|
|
50
|
+
- monto: decimal(12,2), not null
|
|
51
|
+
- fecha: date, not null
|
|
52
|
+
- tipo: enum(CUOTA, MORA, AMBOS), not null
|
|
53
|
+
- metodo_pago: enum(EFECTIVO, TRANSFERENCIA), not null
|
|
54
|
+
- empleado_id: int FK -> usuarios.id, not null
|
|
55
|
+
|
|
56
|
+
### moras
|
|
57
|
+
- id: int PK
|
|
58
|
+
- uuid: char(64) UK, not null
|
|
59
|
+
- semanas_prestamo_id: int FK -> semanas_prestamo.id, not null
|
|
60
|
+
- monto: decimal(12,2), not null
|
|
61
|
+
- fecha: date, not null
|
|
62
|
+
- estado: enum(PAGADA, PENDIENTE, CANCELADA), not null
|
|
63
|
+
- metodo_pago: enum(EFECTIVO, TRANSFERENCIA)
|
|
64
|
+
|
|
65
|
+
## Relaciones
|
|
66
|
+
|
|
67
|
+
- prestamos.usuario_id: 1:N "solicita"
|
|
68
|
+
- semanas_prestamo.prestamo_id: 1:N "tiene"
|
|
69
|
+
- pagos.semanas_prestamo_id: 1:N "cubre"
|
|
70
|
+
- moras.semanas_prestamo_id: 1:N "genera"
|
|
71
|
+
- pagos.empleado_id: 1:N "registra"
|