Esquema
.erd.json es el formato de documento del editor. Lee esta página si necesitas generar, validar o migrar un documento fuera del editor.
Esta página describe la forma de almacenamiento, el documento tal como lo contiene un archivo, que escribe toda versión desde la 4.0.0. Es lo que devuelve editor.value, lo que escribe la exportación JSON y la única forma que acepta el JSON Schema publicado. Su version es '3.0.0', como en todo archivo v3 que guardó una versión anterior, así que version no distingue un archivo antiguo de uno nuevo. setInitialValue(), el setter de value y setSchemaJSON() leen esta forma, cualquier archivo que haya guardado una versión anterior y un documento .vuerd v2. Antes de la 4.0.0, value devolvía el documento entero tal como lo mantenía el editor, así que un archivo guardado entonces contiene más (consulta Forma de almacenamiento).
El runtimeValue de un editor es otra serialización, que esta página no describe. Inicializa a otro editor o a una réplica, y una sala de Yjs lo guarda en su instantánea; nunca debe estar en un archivo, y el JSON Schema rechaza cualquiera que contenga una entidad.
Forma de almacenamiento
La forma de almacenamiento contiene solo las entidades activas: cada tabla listada en doc.tableIds, las columnas que listan esas tablas, las relaciones entre dos tablas conservadas, los índices de las tablas conservadas, con las columnas de índice cuya columna aún lista la tabla, las notas y los grupos de tablas listados y, desde la 4.2.0, las palabras, los términos y los dominios de las hojas del diccionario que contienen algún valor además de su id. No contiene nada que un editor calcule al cargar o mantenga solo mientras está abierto: ni el orden de apilamiento, ni los anchos medidos, ni las marcas de clave, ni si una relación es identificadora, cómo se dibuja su extremo padre o dónde se une a sus tablas. Cada carga lo vuelve a calcular a partir de lo que contiene el archivo.
Todas las colecciones salvo los diccionarios tienen como claves los ids, en orden de unidades de código, con las columnas agrupadas primero por tableId y las columnas de índice por indexId. Desde la 4.2.0, wordEntities, termEntities y domainEntities van después de todas las demás colecciones, en ese orden, y cada una se escribe como un encabezado y filas, una fila por línea (consulta Filas de los diccionarios). Cada entidad escribe sus campos en un orden fijo, y el texto se sangra con dos espacios y termina con un salto de línea. Así, el mismo documento escribe siempre los mismos bytes, una edición cambia solo lo que toca y un archivo guardado en un ordenador con otras fuentes se vuelve a abrir con el mismo value.
VS Code, Obsidian y el plugin de JetBrains escriben un archivo solo cuando una edición cambia value, así que un archivo que guardó una versión anterior conserva su forma antigua hasta su primera edición.
Desde la 4.2.0, la forma de almacenamiento también deja fuera lo que no contiene nada: cada campo de texto que una entidad o su ui contiene como '' (el name, el comment y el ui.color de una tabla; el name, el comment, el dataType y el default de una columna; el name de un índice; el value y el ui.color de una nota; el name y el color de un grupo de tablas), cada lista de doc y cada colección que no contiene ninguna entrada, y el propio objeto collections en cuanto todas las colecciones están vacías. El texto formado solo por espacios en blanco se escribe tal como está, salvo un nombre lógico, que entonces se deja fuera, y una palabra, un término o un dominio cuyos valores además de su id están todos vacíos o son solo espacios en blanco, que se deja fuera entero. Se siguen escribiendo todos los ids, todas las listas dentro de una entidad y todos los números, 0 incluido. doc se escribe siempre, así que el archivo de un documento nuevo contiene $schema, version, sus ajustes y "doc": {}.
El análisis lee un campo de texto que falta como '' y una colección que falta como vacía, como hacen todas las versiones v3, y la forma de almacenamiento solo deja fuera una lista de doc mientras su colección no contiene nada (consulta Doc). Así, un editor anterior a la 4.2.0 también abre estos archivos, y un programa que lea un archivo por su cuenta debe leer del mismo modo lo que falta. Un archivo que guardó una versión anterior queda, tras su siguiente guardado, sin su texto, sus listas y sus colecciones vacíos, un cambio que se hace una sola vez, y a partir de entonces se guarda byte a byte igual.
La forma de almacenamiento escribe cada ajuste bloqueado con su valor bloqueado (consulta lockSettings), settings.ddlScripts solo mientras un script contiene texto y el groupId de una tabla solo mientras nombra un grupo de tablas que el archivo escribe. Desde la 4.2.0, también escribe settings.nameViewMode solo mientras el valor que escribe no es 'physical', settings.columnOrder en siete entradas donde es posible (consulta Ajustes) y el nameDerived de una tabla solo mientras es true.
Escribe doc.tableGroupIds y tableGroupEntities solo mientras existe un grupo de tablas, un logicalName solo mientras contiene texto distinto de espacios en blanco, el domainId de una columna solo mientras nombra un dominio que el archivo escribe y cada diccionario solo mientras contiene una fila que el archivo escribe.
Un archivo guardado antes de la 4.0.0 contiene el documento entero tal como lo mantenía entonces un editor, con sus entidades eliminadas y lo que cada carga calcula. Una carga lo lee, conserva el lugar de cada tabla y nota en la pila (consulta Doc) y vuelve a calcular el resto, y el siguiente guardado escribe solo la forma de almacenamiento.
TypeScript
Los tipos describen la forma de almacenamiento, y cada uno lista sus campos en el orden en que los escribe un archivo. Un campo marcado con ? es uno que la forma de almacenamiento puede dejar fuera, como detalla Forma de almacenamiento, y el análisis lee uno que falta como si no contuviera nada: '', false, ningún grupo de tablas ni dominio, una colección vacía, 'physical' para nameViewMode y dos scripts vacíos para ddlScripts. La excepción es una lista de doc que falta, que el análisis rellena a partir de su colección (consulta Doc). En una fila de diccionario, ? marca los valores antes de los cuales puede terminar una fila (consulta Filas de los diccionarios). Todos los demás campos se escriben siempre.
ERDEditorSchemaV3
type ERDEditorSchemaV3 = {
$schema: 'https://raw.githubusercontent.com/dineug/erd-editor/main/json-schema/schema.json';
version: '3.0.0';
settings: Settings;
doc: Doc;
collections?: {
tableEntities?: Record<string, Table>;
tableColumnEntities?: Record<string, Column>;
relationshipEntities?: Record<string, Relationship>;
indexEntities?: Record<string, Index>;
indexColumnEntities?: Record<string, IndexColumn>;
memoEntities?: Record<string, Memo>;
tableGroupEntities?: Record<string, TableGroup>;
wordEntities?: DictionaryRows; // rows of Word
termEntities?: DictionaryRows; // rows of Term
domainEntities?: DictionaryRows; // rows of Domain
};
};
Toda entidad tiene un id, una cadena opaca, que es su clave en su colección, salvo en los tres diccionarios, donde es el primer valor de una fila. Desde la 4.2.0, cuando una entidad de las siete colecciones con claves tiene un id que falta, está vacío o no es una cadena, el análisis la lee con la clave bajo la que está, y descarta una entrada que no es un objeto, o una sin id cuya clave es ''. Una fila de diccionario se descarta cuando no es un array o su id no es una cadena distinta de ''. Un editor anterior a la 4.2.0 descarta una entidad cuyo id falta o está vacío, así que la forma de almacenamiento sigue escribiendo todos los ids.
Desde la 4.0.0, cada id nuevo, incluido el de una fila de diccionario, es un UUIDv7 escrito en formato Uuid25, 25 dígitos en base 36 en minúscula como 03gzrxjv20bdlcak89q25d2m7, de modo que los ids que genera un editor se ordenan en el orden en que los creó. Un documento conserva los ids que contiene, como los ids nanoid de una versión anterior o los ids de un archivo v2, así que nada debe depender de la forma de un id.
Desde la 4.0.0, ninguna entidad lleva un objeto meta (createAt, updateAt), y se eliminaron los tipos EntityMeta y EntityType. Nada lo escribe, el análisis descarta el meta que lleva un archivo más antiguo y el JSON Schema lo rechaza. Solo servía para temporizar la recolección de elementos no utilizados de las entidades eliminadas, que también ha desaparecido.
Ajustes
type Settings = {
originX: number;
originY: number;
zoomLevel: number;
show: number; // Constants: Show
database: number; // Constants: Database
databaseName: string;
canvasType: string; // Constants: CanvasType
language: number; // Constants: Language
tableNameCase: number; // Constants: NameCase
columnNameCase: number; // Constants: NameCase
bracketType: number; // Constants: BracketType
relationshipDataTypeSync: boolean;
columnOrder: number[]; // Constants: ColumnType
maxWidthComment: number;
lockSettings: number; // Constants: LockSettingType
ddlScripts?: DDLScripts;
nameViewMode?: string; // Constants: NameViewMode
};
type DDLScripts = {
before: string;
after: string;
};
// Constants
const CanvasType = {
ERD: 'ERD',
visualization: '@dineug/erd-editor/builtin-visualization',
schemaSQL: '@dineug/erd-editor/builtin-schema-sql',
generatorCode: '@dineug/erd-editor/builtin-generator-code',
settings: 'settings',
dictionary: '@dineug/erd-editor/builtin-dictionary',
} as const;
const Show = {
tableComment: 1,
columnComment: 2,
columnDataType: 4,
columnDefault: 8,
columnAutoIncrement: 16,
columnPrimaryKey: 32,
columnUnique: 64,
columnNotNull: 128,
relationship: 256,
columnAlternateKey: 512,
hideReferentialAction: 1024,
hideTableGroup: 2048,
hideMemo: 4096,
columnDomain: 8192,
} as const;
const ColumnType = {
columnName: 1,
columnDataType: 2,
columnNotNull: 4,
columnUnique: 8,
columnAutoIncrement: 16,
columnDefault: 32,
columnComment: 64,
columnLogicalName: 128,
columnDomain: 256,
} as const;
const Database = {
MariaDB: 1,
MSSQL: 2,
MySQL: 4,
Oracle: 8,
PostgreSQL: 16,
SQLite: 32,
Databricks: 64,
Snowflake: 128,
} as const;
const Language = {
GraphQL: 1,
csharp: 2,
Java: 4,
Kotlin: 8,
TypeScript: 16,
JPA: 32,
Scala: 64,
Go: 128,
SQLAlchemy: 256,
TypeORM: 512,
Sequelize: 1024,
Drizzle: 2048,
DBML: 4096,
AML: 8192,
Mermaid: 16384,
PHP: 32768,
Doctrine: 65536,
Rust: 131072,
SeaORM: 262144,
Swift: 524288,
Zod: 1048576,
JSONSchema: 2097152,
} as const;
const NameCase = {
none: 1,
camelCase: 2,
pascalCase: 4,
snakeCase: 8,
} as const;
const BracketType = {
none: 1,
doubleQuote: 2,
singleQuote: 4,
backtick: 8,
} as const;
const LockSettingType = {
viewport: 1, // originX, originY and zoomLevel
canvasType: 2,
language: 4,
tableNameCase: 8,
columnNameCase: 16,
bracketType: 32,
unlockNameViewMode: 64, // nameViewMode; set while unlocked
} as const;
const NameViewMode = {
physical: 'physical',
logical: 'logical',
both: 'both',
} as const;
originX y originY son la vista: el punto de la pantalla en el que cae el punto (0, 0) de la escena.
zoomLevel va de 0.1 a 1.5. Un documento guardado con un valor superior a 1 se abre con 1 en un editor anterior a la 3.5.0.
Desde la 4.0.0, los ajustes no llevan width, height, scrollTop, scrollLeft, relationshipOptimization ni ignoreSaveSettings. Nada los escribe, el analizador no conserva ninguno y el JSON Schema rechaza un archivo que todavía los tenga.
canvasType es la pestaña en la que se abre un documento. Un documento guardado en la pestaña Visualización contiene '@dineug/erd-editor/builtin-visualization', pero no si se mostraba el modo Graph o Flow, y un editor recién creado muestra esa pestaña en modo Graph.
Desde la 4.0.0, mientras el bloqueo Canvas Type está activado, como lo está en un documento nuevo, el documento conserva la pestaña que se mostraba al bloquearlo, y cambiar de pestaña deja value como estaba. Un bloqueo activado en la pestaña Configuración guarda la pestaña de la que venía el lector, y un 'settings' bloqueado, que solo puede escribir una edición manual, se abre en 'ERD'.
Desde la 4.2.0, canvasType también puede ser '@dineug/erd-editor/builtin-dictionary', la pestaña Diccionario, que el bloqueo Canvas Type guarda igual que las demás. Un editor anterior a la 4.2.0 conserva ese valor, pero no muestra ninguna pestaña bajo su barra de herramientas hasta que el lector elige una.
No se serializa nada del estado propio del modo Flow: su colocación, zoom, desplazamiento de la vista, vista de filas y tablas en las que se centra se quedan en el editor y, desde la 4.2.0, también las vistas por las que retroceden y avanzan Previous table y Next table. Así, originX, originY y zoomLevel describen siempre el lienzo ERD.
show y lockSettings son máscaras de bits: combina los indicadores con OR.
columnOrder es un array que contiene cada valor de ColumnType una sola vez, en el orden de visualización; desde la 4.2.0, un documento puede escribirlo con siete de los nueve, como describe más abajo el párrafo sobre el orden de columnas.
database, language, tableNameCase, columnNameCase y bracketType contienen cada uno exactamente un valor, y el JSON Schema rechaza un valor combinado.
El show de un documento nuevo es 431: tableComment, columnComment, columnDataType, columnDefault, columnPrimaryKey, columnNotNull y relationship.
Desde la 3.10.0, hay dos indicadores de show más, ambos desactivados en un documento nuevo y en todo documento guardado antes de la 3.10.0.
columnAlternateKey (512) es la opción de vista Alternate Key. Con el indicador activado, marca las columnas de cada índice único de dos o más columnas como AK1.1, AK1.2, etc. Empieza desactivado, así que ningún diagrama existente cambia de ancho.
hideReferentialAction (1024) funciona al revés: cuando está activado, oculta las etiquetas ON DELETE y ON UPDATE de los conectores, así que se muestran de forma predeterminada. La opción de vista Referential Actions está marcada mientras el indicador está desactivado. No cambia el tamaño de ninguna tabla.
Un editor anterior a la 3.10.0 conserva show como un número entero, así que ambos indicadores sobreviven a un guardado allí.
Desde la 4.0.0, hay dos indicadores de show más, ambos desactivados en un documento nuevo y en todo documento guardado antes de la 4.0.0. Como hideReferentialAction, cada uno oculta lo que nombra, así que los grupos de tablas y las notas se muestran de forma predeterminada.
hideTableGroup (2048) oculta los grupos de tablas, y hideMemo (4096) oculta todas las notas. Son las opciones de vista Table Groups y Memos, cada una marcada mientras su indicador está desactivado. Ninguno de los dos cambia el tamaño de ninguna tabla.
Un editor anterior a la 4.0.0 conserva show como un número entero, así que ambos indicadores sobreviven a un guardado allí.
Desde la 4.2.0, hay un indicador de show más, columnDomain (8192), desactivado en un documento nuevo y en todo documento guardado antes de la 4.2.0, así que el show de un documento nuevo sigue siendo 431. Es la opción de vista Domain: con el indicador activado, cada fila de columna muestra una celda Dominio, que ensancha las tablas. Empieza desactivado, así que ningún diagrama existente cambia de ancho.
Un editor anterior a la 4.2.0 conserva show como un número entero, así que el indicador sobrevive a un guardado allí.
Desde la 4.2.0, ColumnType tiene nueve valores. columnLogicalName (128) coloca la celda del nombre lógico, que una fila de columna solo dibuja en la vista Both Names, y columnDomain (256), la celda Dominio. Son las filas Logical Name y Domain del orden de columnas de la pestaña Configuración. Un editor mantiene un orden de los nueve, y el de un documento nuevo es 128, 1, 2, 256, 4, 8, 16, 32, 64.
La forma de almacenamiento escribe el orden en siete entradas, dejando fuera 128 y 256, mientras 128 está justo antes de columnName y 256 justo después de columnDataType. Así, un documento nuevo sigue escribiendo 1, 2, 4, 8, 16, 32, 64, y un archivo cuyo orden nunca los movió conserva sus bytes. En caso contrario, escribe los nueve.
El análisis coloca los dos en esos lugares de un orden de siete entradas, sea cual sea el orden de las siete, y toma tal cual nueve entradas que contengan todos los tipos.
Desde la 5.0.0 acepta también cualquier otro orden. Conserva una sola vez cada ColumnType que conoce, en el orden dado, y descarta cualquier otra entrada: un valor que ningún ColumnType nombra, como un tipo que añada una versión posterior, y una segunda entrada del mismo tipo. Cada tipo que le falta al orden va justo después del tipo más cercano anterior a él en el orden predeterminado que el orden contiene o, si no hay ninguno anterior, justo antes del más cercano posterior, que es como 128 y 256 encuentran su lugar en siete entradas. Solo un orden que no nombra ningún tipo que conozca, o un valor que no es un array, se lee como el orden predeterminado.
Así, un archivo que guardó una versión posterior se abre con su orden de los tipos que esta versión conoce, y un guardado aquí escribe ese orden sin los demás. Antes de la 5.0.0, el análisis leía cualquier otro orden como el predeterminado, así que un archivo así se abría con el orden de columnas restablecido. El JSON Schema admite siete o nueve enteros.
Desde la 4.0.0, Language tiene ocho destinos más del Generador de código, de Mermaid a JSONSchema. Un language que el analizador no conoce se lee como GraphQL, así que un editor anterior a la 4.0.0 abre en GraphQL un documento guardado con uno de ellos, y al guardar allí se escribe GraphQL.
Desde la 4.0.0, lockSettings ocupa el lugar de ignoreSaveSettings, y LockSettingType el de SaveSettingType, que se eliminó. lockSettings nombra los ajustes que un documento guarda tal como estaban cuando se bloquearon. viewport abarca originX, originY y zoomLevel juntos, ya que un origen guardado sin su zoom se abre en otro sitio, y cada uno de los demás bits abarca el campo del que toma su nombre. Son las filas de Lock de la pestaña Configuración.
Un archivo contiene cada ajuste bloqueado con su valor bloqueado, muestre lo que muestre el editor, y cada uno de los demás ajustes tal como está. Así, mientras el bloqueo correspondiente está activado, desplazarse y hacer zoom, cambiar de pestaña, cambiar el lenguaje del Generador de código, un estilo de nombres o el tipo de delimitador, o cambiar la vista de nombres deja el archivo como estaba. Al bloquear se toma el valor que el ajuste tiene en ese momento, y el análisis toma el valor bloqueado del campo guardado.
Un documento que parte de cero —un editor o un almacén de replicación nuevos, o un valor vacío pasado a value o a setInitialValue()— tiene lockSettings en 63, con todos los bloqueos activados. Un documento cuyos settings no llevan lockSettings —todo archivo guardado antes de la 4.0.0, sea cual sea su ignoreSaveSettings, y todo documento v2— también se abre con todos los bloqueos activados: su vista y su pestaña donde están las de un documento nuevo (originX y originY a 0, zoomLevel a 1, la pestaña ERD), y su lenguaje, sus estilos de nombres y su tipo de delimitador bloqueados en los valores que guardó. Un documento que nombra sus bloqueos los conserva, 0 incluido, junto con todos los valores que guardó.
El análisis conserva todos los bits de lockSettings, también los desconocidos, así que un bloqueo que añada una versión posterior sobrevive a un guardado aquí; el JSON Schema solo comprueba que sea un entero. Un editor anterior a la 4.0.0 descarta lockSettings al guardar y escribe la vista y la pestaña tal como están, así que el archivo vuelve a abrirse aquí como uno guardado antes de la 4.0.0.
Desde la 4.2.0, hay un séptimo bloqueo, unlockNameViewMode (64), la fila Name View, que abarca nameViewMode. Su bit se lee al revés que los demás bits de bloqueo, como los bits de ocultación de Show: activado, la vista de nombres está desbloqueada, y desactivado, bloqueada. Así, 63 sigue significando todos los bloqueos activados, y un documento nuevo lo contiene con la vista de nombres bloqueada en 'physical'. Un archivo guardado antes de la 4.2.0 tiene el bit desactivado, sean cuales sean sus demás bloqueos, 0 incluido, así que se abre con la vista de nombres bloqueada en 'physical'. Un documento con todos los bloqueos desactivados contiene 64, y uno con todos los demás bloqueos activados y la vista de nombres desbloqueada contiene 127. Comprueba este bloqueo a la inversa: está activado mientras (lockSettings & 64) === 0.
Mientras el bit está desactivado, un archivo contiene nameViewMode con la vista bloqueada, muestre lo que muestre cualquier editor, y mientras está activado, la vista tal como está. Lo que muestra cada editor, con el bloqueo activado o desactivado, se describe en Lock.
Un editor de la 4.0.0 o la 4.1.0 conserva el bit al guardar, pero descarta nameViewMode, así que el documento se vuelve a abrir aquí en 'physical', con su bloqueo como estaba.
Desde la 4.0.0, ddlScripts contiene los dos scripts de la pestaña Esquema SQL, que escribe el DDL de todas las bases de datos: before después de la cabecera y antes de las tablas, after tras el DDL generado. El DDL escribe cada uno con saltos de línea LF, sin sus líneas en blanco iniciales ni sus espacios en blanco finales y, en MSSQL, terminado en GO, como se describe en Scripts previos y posteriores; el propio ddlScripts conserva cada script tal como se escribió. La clave solo se escribe mientras alguno de los scripts contiene texto, y entonces con ambos; una clave que falta, o un script que no es una cadena, se lee como ''. Las opciones Statements, Header y Tables de la pestaña y, desde la 4.2.0, su interruptor Write logical names into empty comments no se guardan en el documento.
Un editor anterior a la 4.0.0 descarta los scripts al cargar un documento, así que al guardar allí se pierden.
Desde la 4.2.0, nameViewMode es la vista de nombres, los nombres que dibuja el diagrama: 'physical', el nombre de cada tabla y columna; 'logical', su nombre lógico en el lugar del nombre, y 'both', el nombre lógico y el nombre. Los menús los llaman Physical Names, Logical Names y Both Names. La forma de almacenamiento lo escribe al final, después de ddlScripts, y solo mientras el valor que escribe no es 'physical'. Un valor que falta, o uno que el analizador no conoce, se lee como 'physical', y el JSON Schema solo acepta "logical" y "both".
Un editor anterior a la 4.2.0 descarta nameViewMode al cargar un documento.
Database, Language, Show, ColumnType, ColumnOption, LockSettingType y ReferentialAction solo admiten añadir valores al final. Un documento guardado almacena el número, así que un nuevo proveedor, destino de generación de código, indicador, tipo de columna, opción de columna, bloqueo o acción toma el siguiente bit en lugar de un hueco intermedio.
Doc
type Doc = {
tableIds?: string[];
relationshipIds?: string[];
indexIds?: string[];
memoIds?: string[];
tableGroupIds?: string[];
};
Cada lista es el orden de un tipo de entidad, que leen el DDL, la ordenación de tablas y el orden de dibujo. Cada una contiene solo los ids de las entidades que escribe el archivo, cada uno una sola vez, en el orden listado y, desde la 4.2.0, una lista que no contiene ninguno se deja fuera. Desde la 4.0.0, tableGroupIds es el orden de los grupos de tablas. Los diccionarios no tienen aquí ninguna lista, porque sus filas están en el orden de cada hoja (consulta Filas de los diccionarios), y el JSON Schema no acepta ninguna otra clave en doc.
Desde la 4.2.0, el análisis lee una lista que el documento deja fuera, o que contiene como algo que no es un array, como todas las entradas que contiene su colección, cada id una sola vez, en el orden en que están; un array vacío sigue vacío, y entonces todas las entradas de su colección se leen como eliminadas. Un editor anterior a la 4.2.0 lee una lista que falta como vacía, así que la forma de almacenamiento sigue escribiendo cada lista siempre que su colección contiene una entidad.
Desde la 4.0.0, un archivo no contiene orden de apilamiento. Una carga apila las tablas y las notas listadas según su posición en sus listas, con las posteriores delante y todas las notas por encima de todas las tablas, y los grupos de tablas del mismo modo entre ellos, detrás de las tablas. Una tabla o una nota de un archivo guardado antes de la 4.0.0 lleva un zIndex en su ui, que una carga conserva como su lugar en la pila y que el siguiente guardado deja fuera. Por eso, traer una tabla o una nota al frente se pierde al volver a abrir el archivo.
Colección: tableEntities
type Table = {
id: string;
name?: string;
logicalName?: string;
comment?: string;
columnIds: string[];
groupId?: string;
nameDerived?: true;
ui: TableUI;
};
type TableUI = {
x: number;
y: number;
color?: string;
};
Desde la 4.0.0, una tabla lleva groupId, el id del grupo de tablas al que pertenece. Un groupId que falta o está vacío, o que no nombra ningún grupo de doc.tableGroupIds, significa que no pertenece a ninguno, y la forma de almacenamiento solo lo escribe mientras nombra un grupo conservado.
Desde la 4.2.0, una tabla lleva logicalName, el nombre que dibujan las vistas Logical Names y Both Names, '' si no tiene ninguno, y nameDerived, true mientras name sea el que los diccionarios derivaron del nombre lógico. Mientras está activado, un nuevo nombre lógico vuelve a derivar el nombre; mientras no lo está, el nombre lo escribió alguien, y un nuevo nombre lógico no lo toca salvo que esté vacío o sea solo espacios en blanco. Cambiar el nombre a mano lo desactiva, y Derive Physical Names Again reescribe incluso un nombre que alguien escribió y lo activa allí donde haya un nombre lógico.
La forma de almacenamiento escribe logicalName después de name, tal como se escribió, solo mientras contiene texto distinto de espacios en blanco, y nameDerived después de groupId solo mientras es true, el único valor que acepta el JSON Schema. Un logicalName que falta se lee como '' y un nameDerived que falta, como false, así que todo nombre de un archivo guardado antes de la 4.2.0 cuenta como escrito por alguien.
Un editor anterior a la 4.2.0 descarta ambos al cargar un documento, así que al guardar allí se pierde el nombre lógico de todas las tablas.
Colección: tableColumnEntities
type Column = {
id: string;
tableId: string;
name?: string;
comment?: string;
dataType?: string;
default?: string;
options: number; // Constants: ColumnOption
logicalName?: string;
domainId?: string;
};
// Constants
const ColumnOption = {
autoIncrement: 1,
primaryKey: 2,
unique: 4,
notNull: 8,
nameDerived: 16,
} as const;
Desde la 4.0.0, un archivo no contiene marcas de clave: cada carga marca una columna como clave principal a partir del bit primaryKey de options, y como clave externa mientras una relación termina en ella en su tabla.
Un editor anterior a la 4.0.0 muestra las columnas de un archivo guardado aquí sin sus iconos de clave principal.
Desde la 4.2.0, una columna lleva logicalName, como una tabla, y domainId, el id del dominio que vincula, '' si no vincula ninguno. Las ediciones en un editor mantienen una columna vinculada en el tipo de datos de su dominio, como se describe en Dominios y tipos de datos. Sin embargo, el análisis no cambia el tipo de ninguna columna, así que un archivo escrito en otro sitio puede dejar una columna vinculada con otro tipo, y lo mismo pueden hacer las ediciones cruzadas de dos colaboradores; la hoja Comprobaciones lista cada caso como Domain type mismatch. El análisis vacía un domainId que no nombra ningún dominio que contenga el archivo. Después de options, la forma de almacenamiento escribe logicalName según la regla de las tablas, y domainId solo mientras nombra un dominio que el archivo escribe, así que una columna vinculada con un dominio eliminado, o con uno que el archivo deja fuera, se escribe sin el vínculo y con el tipo de datos que contiene.
ColumnOption.nameDerived (16) es el indicador de nombre derivado de la columna, que se guarda en options con los demás bits y significa lo mismo que el nameDerived de una tabla. Por ejemplo, una clave principal no nula cuyo nombre derivaron los diccionarios contiene options 26.
Un editor anterior a la 4.2.0 descarta logicalName y domainId al cargar un documento, así que al guardar allí se pierden. Conserva options como un número entero, así que el bit nameDerived sobrevive a un guardado allí.
Colección: relationshipEntities
type Relationship = {
id: string;
relationshipType: number; // Constants: RelationshipType
onDelete: number; // Constants: ReferentialAction
onUpdate: number; // Constants: ReferentialAction
start: RelationshipPoint;
end: RelationshipPoint;
};
type RelationshipPoint = {
tableId: string;
columnIds: string[];
};
// Constants
const RelationshipType = {
ZeroOne: 2,
ZeroN: 4,
OneOnly: 8,
OneN: 16,
} as const;
const ReferentialAction = {
none: 1,
noAction: 2,
cascade: 4,
setNull: 8,
setDefault: 16,
restrict: 32,
} as const;
Desde la 3.10.0, una relación lleva onDelete y onUpdate, sus acciones ON DELETE y ON UPDATE. Cada uno contiene exactamente un valor de ReferentialAction. none, el valor predeterminado, no escribe ninguna cláusula, así que se aplica el valor predeterminado de la propia base de datos. Los otros cinco representan NO ACTION, CASCADE, SET NULL, SET DEFAULT y RESTRICT. Esquema SQL solo escribe una cláusula para una base de datos que acepte su acción.
La forma de almacenamiento siempre escribe ambos y, desde la 4.0.0, el JSON Schema los exige y solo comprueba que cada uno sea un entero. El análisis sigue leyendo como none un campo que falta, como en todo documento guardado antes de la 3.10.0, y lo mismo hace con un valor fuera de la lista.
Un editor anterior a la 3.10.0 no conoce estos campos y los descarta al cargar un documento, así que al guardar allí se pierden todas las acciones.
Desde la 4.0.0, cada carga lee si una relación es identificadora, y cómo se dibuja su extremo padre, a partir de las columnas en las que termina que la tabla hija aún lista. Es identificadora, una línea continua, mientras todas esas columnas son clave principal, y su extremo padre son dos barras mientras todas esas columnas son NOT NULL, y un círculo y una barra en caso contrario. Una a la que no le queda ninguna de esas columnas es no identificadora, con dos barras, como empieza una relación nueva. Consulta Cómo leer un conector.
Colección: indexEntities
type Index = {
id: string;
name?: string;
tableId: string;
indexColumnIds: string[];
unique: boolean;
};
Colección: indexColumnEntities
type IndexColumn = {
id: string;
indexId: string;
columnId: string;
orderType: number; // Constants: OrderType
};
// Constants
const OrderType = {
ASC: 1,
DESC: 2,
} as const;
Colección: memoEntities
type Memo = {
id: string;
value?: string;
ui: MemoUI;
};
type MemoUI = {
x: number;
y: number;
width: number;
height: number;
color?: string;
};
Desde la 4.0.0, las tablas y las notas comparten una misma pila, así que traer una tabla al frente puede colocarla sobre una nota. Una carga pone todas las notas por encima de todas las tablas, como se describe en Doc. Una nota de un archivo guardado antes de la 4.0.0 conserva el zIndex que guardó, que procedía del mismo contador que el de las tablas, así que una nota que una versión anterior dibujó sobre todas las tablas puede abrirse debajo de una tabla traída al frente después de ella.
Colección: tableGroupEntities
type TableGroup = {
id: string;
name?: string;
color?: string;
ui: TableGroupUI;
};
type TableGroupUI = {
x: number;
y: number;
width: number;
height: number;
};
Desde la 4.0.0, un documento puede contener grupos de tablas: rectángulos con nombre y color que se dibujan detrás de las tablas. Una tabla se une a uno mediante su propio groupId, así que un grupo no contiene ninguna lista de miembros. La forma de almacenamiento escribe la colección, como doc.tableGroupIds, solo mientras existe un grupo, y un documento sin ella, como uno guardado antes de la 4.0.0, no tiene grupos. Show.hideTableGroup los oculta.
Un editor anterior a la 4.0.0 descarta los grupos y el groupId de cada tabla al cargar un documento, así que al guardar allí se pierden todos los grupos.
Filas de los diccionarios
Desde la 4.2.0, un documento contiene tres diccionarios, las hojas Words, Terms y Domains de la pestaña Diccionario, en wordEntities, termEntities y domainEntities. Todos los campos de una palabra, un término o un dominio son cadenas, y ninguno tiene ui. La hoja Checks se calcula a partir de los diccionarios y el diagrama, y no se guarda.
type DictionaryRows = {
fields: string[];
rows: string[][];
};
Ninguno de los tres tiene los ids como claves. Cada uno se escribe como un encabezado y filas: fields nombra una vez los campos de la entidad, el id primero, y cada fila contiene los valores de una entidad en ese orden. Los tipos de abajo listan los campos de cada entidad en ese orden. Una fila siempre conserva su id y su nombre, pero los valores vacíos finales posteriores al nombre se dejan fuera, así que un valor vacío anterior a uno que se conserva sigue siendo '', y el análisis lee como '' un valor que le falta a una fila. Cada fila se escribe en una línea propia como JSON compacto, como en estas dos palabras de un archivo:
"wordEntities": {
"fields": [
"id",
"name",
"abbreviation",
"englishName",
"description",
"synonyms",
"forbiddenWords"
],
"rows": [
["w1","Customer","CUST","customer"],
["w2","Number","NO","number","","No, Num","Nbr"]
]
}
La forma de almacenamiento escribe las filas de cada hoja en el orden de la hoja, sin campo de orden, así que las filas de un archivo son los miembros de un diccionario y su orden. Deja fuera una fila cuyos valores además de su id están todos vacíos o son solo espacios en blanco, como una que se añadió y nunca se rellenó, o que se vació, y todo vínculo con un dominio así o con uno eliminado: el domainId de una columna se deja fuera, y el de un término se escribe como ''; el propio término se deja fuera si no contiene nada más.
El análisis lee las filas en el orden en que están, así que cada hoja las lista en el orden en que las escribió el archivo.
Un documento sin los diccionarios, como uno guardado antes de la 4.2.0, no tiene ninguno. Un editor anterior a la 4.2.0 descarta los tres al cargar un documento, así que al guardar allí se pierden todas las palabras, los términos y los dominios.
Colección: wordEntities
type Word = {
id: string;
name: string;
abbreviation?: string;
englishName?: string;
description?: string;
synonyms?: string;
forbiddenWords?: string;
};
Una palabra es una de las palabras de las que se compone un nombre lógico, y abbreviation es lo que la representa en un nombre físico. synonyms lista otras grafías de la palabra, y forbiddenWords, palabras que no deben usarse en su lugar, en ambos casos separadas por comas.
Colección: termEntities
type Term = {
id: string;
name: string;
physicalName?: string;
domainId?: string;
description?: string;
synonyms?: string;
};
Un término es un nombre lógico completo. Una tabla o columna cuyo logicalName coincide con name deriva physicalName o, mientras este está vacío, un nombre compuesto a partir de las abreviaturas de las palabras, y una columna también toma el dominio que nombra domainId, '' si no hay ninguno (consulta Derivar nombres físicos). synonyms va separado por comas. El análisis vacía un domainId que no nombra ningún dominio que contenga el archivo, como en una columna.
Colección: domainEntities
type Domain = {
id: string;
name: string;
category?: string;
dataType?: string;
description?: string;
};
Un dominio es un tipo de datos con nombre; dataType lo contiene como lo hace una columna, longitud incluida, por ejemplo NUMERIC(10). Una columna o un término vincula un dominio por su id, y el editor da a cada columna vinculada el tipo de datos del dominio (consulta Dominios y tipos de datos).
JSON Schema
El archivo de esquema canónico se publica en json-schema/schema.json y se puede referenciar directamente con $schema.
{
"$schema": "https://raw.githubusercontent.com/dineug/erd-editor/main/json-schema/schema.json",
"version": "3.0.0"
}
Pon $schema al principio de un archivo .erd.json y los editores que entienden JSON Schema, como VS Code, validan el documento y autocompletan sus campos mientras editas.
Desde la 4.0.0, el esquema describe solo la forma de almacenamiento. Todo objeto con campos con nombre está cerrado (additionalProperties: false), todo campo que la forma de almacenamiento escribe siempre es obligatorio, cada campo marcado con ? en los tipos de arriba se nombra pero no es obligatorio, y no se nombra ningún otro campo. Por eso rechaza un archivo guardado antes de la 4.0.0, con su meta, sus anchos, su zIndex, su ignoreSaveSettings y lo demás, hasta que un editor de la 4.0.0 o posterior vuelva a guardar ese archivo. Un archivo guardado por la 3.2.0 o posterior ya nombra la URL de este esquema, que apunta a la rama main, así que un editor que valida con él señala ahora el archivo. Un archivo guardado por la 3.0.0 o la 3.1.0, o un documento v2, no nombra ningún $schema.
Desde la 4.2.0, el esquema ya no exige los campos de texto de una entidad, ni ninguna lista de doc, ni ninguna colección, ni el propio objeto collections, que la forma de almacenamiento deja fuera mientras no contienen nada. Sigue aceptando un archivo guardado por la 4.0.0 o la 4.1.0. Nombra los campos nuevos: nameViewMode, que solo admite "logical" y "both"; el logicalName de una tabla y su nameDerived, que solo admite true; el logicalName y el domainId de una columna, y los tres diccionarios, cada uno con su encabezado y sus filas de cadenas. canvasType lista la pestaña Diccionario, columnOrder admite siete o nueve enteros, y las descripciones de show, columnOrder, lockSettings y options nombran los bits nuevos.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://raw.githubusercontent.com/dineug/erd-editor/main/json-schema/schema.json",
"title": "ERD Editor document",
"description": "The storage form an ERD Editor file holds (.erd, .erd.json, .vuerd, .vuerd.json): the live entities alone, each collection keyed in id order but the dictionaries, a header and one row per entry in document order, without what an editor derives on load or keeps while it is open, without an entity's text field while it is empty, which reads as the empty string, and without an empty list or collection, which reads as none",
"type": "object",
"properties": {
"$schema": {
"type": "string"
},
"version": {
"description": "Version of the schema",
"const": "3.0.0"
},
"settings": {
"$ref": "#/$defs/settings"
},
"doc": {
"$ref": "#/$defs/doc"
},
"collections": {
"description": "The entities of each kind, a kind with none left out",
"type": "object",
"properties": {
"tableEntities": {
"$ref": "#/$defs/tableEntities"
},
"tableColumnEntities": {
"$ref": "#/$defs/tableColumnEntities"
},
"relationshipEntities": {
"$ref": "#/$defs/relationshipEntities"
},
"indexEntities": {
"$ref": "#/$defs/indexEntities"
},
"indexColumnEntities": {
"$ref": "#/$defs/indexColumnEntities"
},
"memoEntities": {
"$ref": "#/$defs/memoEntities"
},
"tableGroupEntities": {
"$ref": "#/$defs/tableGroupEntities"
},
"wordEntities": {
"$ref": "#/$defs/wordEntities"
},
"termEntities": {
"$ref": "#/$defs/termEntities"
},
"domainEntities": {
"$ref": "#/$defs/domainEntities"
}
},
"additionalProperties": false
}
},
"required": ["$schema", "version", "settings", "doc"],
"additionalProperties": false,
"$defs": {
"settings": {
"type": "object",
"properties": {
"originX": {
"type": "number"
},
"originY": {
"type": "number"
},
"zoomLevel": {
"type": "number",
"minimum": 0.1,
"maximum": 1.5
},
"show": {
"description": "bit value (tableComment: 1) | (columnComment: 2) | (columnDataType: 4) | (columnDefault: 8) | (columnAutoIncrement: 16) | (columnPrimaryKey: 32) | (columnUnique: 64) | (columnNotNull: 128) | (relationship: 256) | (columnAlternateKey: 512) | (hideReferentialAction: 1024) | (hideTableGroup: 2048) | (hideMemo: 4096) | (columnDomain: 8192); the three hide bits hide what they name while set",
"type": "integer"
},
"database": {
"description": "bit value (MariaDB: 1) | (MSSQL: 2) | (MySQL: 4) | (Oracle: 8) | (PostgreSQL: 16) | (SQLite: 32) | (Databricks: 64) | (Snowflake: 128)",
"type": "integer",
"enum": [1, 2, 4, 8, 16, 32, 64, 128]
},
"databaseName": {
"type": "string"
},
"canvasType": {
"enum": [
"ERD",
"@dineug/erd-editor/builtin-visualization",
"@dineug/erd-editor/builtin-schema-sql",
"@dineug/erd-editor/builtin-generator-code",
"settings",
"@dineug/erd-editor/builtin-dictionary"
]
},
"language": {
"description": "bit value (GraphQL: 1) | (csharp: 2) | (Java: 4) | (Kotlin: 8) | (TypeScript: 16) | (JPA: 32) | (Scala: 64) | (Go: 128) | (SQLAlchemy: 256) | (TypeORM: 512) | (Sequelize: 1024) | (Drizzle: 2048) | (DBML: 4096) | (AML: 8192) | (Mermaid: 16384) | (PHP: 32768) | (Doctrine: 65536) | (Rust: 131072) | (SeaORM: 262144) | (Swift: 524288) | (Zod: 1048576) | (JSONSchema: 2097152)",
"type": "integer",
"enum": [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152]
},
"tableNameCase": {
"description": "bit value (none: 1) | (camelCase: 2) | (pascalCase: 4) | (snakeCase: 8)",
"type": "integer",
"enum": [1, 2, 4, 8]
},
"columnNameCase": {
"description": "bit value (none: 1) | (camelCase: 2) | (pascalCase: 4) | (snakeCase: 8)",
"type": "integer",
"enum": [1, 2, 4, 8]
},
"bracketType": {
"description": "bit value (none: 1) | (doubleQuote: 2) | (singleQuote: 4) | (backtick: 8)",
"type": "integer",
"enum": [1, 2, 4, 8]
},
"relationshipDataTypeSync": {
"type": "boolean"
},
"columnOrder": {
"description": "bit value (columnName: 1) | (columnDataType: 2) | (columnNotNull: 4) | (columnUnique: 8) | (columnAutoIncrement: 16) | (columnDefault: 32) | (columnComment: 64) | (columnLogicalName: 128) | (columnDomain: 256); seven entries without the last two while the logical name stands just before the name and the domain just after the data type, all nine otherwise",
"type": "array",
"prefixItems": [
{ "type": "integer" },
{ "type": "integer" },
{ "type": "integer" },
{ "type": "integer" },
{ "type": "integer" },
{ "type": "integer" },
{ "type": "integer" },
{ "type": "integer" },
{ "type": "integer" }
],
"anyOf": [
{ "minItems": 7, "maxItems": 7 },
{ "minItems": 9, "maxItems": 9 }
]
},
"maxWidthComment": {
"type": "integer"
},
"lockSettings": {
"description": "bit value (viewport: 1) | (canvasType: 2) | (language: 4) | (tableNameCase: 8) | (columnNameCase: 16) | (bracketType: 32) | (unlockNameViewMode: 64); a locked setting is saved as it stood when locked, the viewport being originX, originY and zoomLevel. The last bit reads the other way round: set, the name view mode is unlocked, and clear, as in a file saved before it, locked",
"type": "integer"
},
"ddlScripts": {
"description": "SQL the Schema SQL writes as is for every database: before after the header and ahead of the tables, after past the generated DDL. Absent while both are empty",
"type": "object",
"properties": {
"before": { "type": "string" },
"after": { "type": "string" }
},
"required": ["before", "after"],
"additionalProperties": false
},
"nameViewMode": {
"description": "The names the diagram shows: the logical ones, or both the physical and the logical. Absent while it shows the physical names, the default",
"enum": ["logical", "both"]
}
},
"required": [
"originX",
"originY",
"zoomLevel",
"show",
"database",
"databaseName",
"canvasType",
"language",
"tableNameCase",
"columnNameCase",
"bracketType",
"relationshipDataTypeSync",
"columnOrder",
"maxWidthComment",
"lockSettings"
],
"additionalProperties": false
},
"doc": {
"description": "The order of each kind of entity, which the DDL, the sort and the draw order read, a kind with none left out. A list goes out whenever its collection holds an entity, since a reader that finds none lists none",
"type": "object",
"properties": {
"tableIds": {
"type": "array",
"items": {
"type": "string"
}
},
"relationshipIds": {
"type": "array",
"items": {
"type": "string"
}
},
"indexIds": {
"type": "array",
"items": {
"type": "string"
}
},
"memoIds": {
"type": "array",
"items": {
"type": "string"
}
},
"tableGroupIds": {
"description": "Order of the table groups. Written while a group exists; absent means none",
"type": "array",
"items": {
"type": "string"
}
}
},
"additionalProperties": false
},
"tableEntities": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"logicalName": {
"description": "The name the logical view shows; absent means none",
"type": "string"
},
"comment": {
"type": "string"
},
"columnIds": {
"type": "array",
"items": {
"type": "string"
}
},
"groupId": {
"description": "Id of the table group in doc.tableGroupIds the table belongs to; absent means none",
"type": "string"
},
"nameDerived": {
"description": "The dictionaries filled the name, so a new logical name derives it again; absent means a name someone wrote",
"type": "boolean",
"const": true
},
"ui": {
"type": "object",
"properties": {
"x": {
"type": "number"
},
"y": {
"type": "number"
},
"color": {
"type": "string"
}
},
"required": ["x", "y"],
"additionalProperties": false
}
},
"required": ["id", "columnIds", "ui"],
"additionalProperties": false
}
},
"tableColumnEntities": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"tableId": {
"type": "string"
},
"name": {
"type": "string"
},
"comment": {
"type": "string"
},
"dataType": {
"type": "string"
},
"default": {
"type": "string"
},
"options": {
"description": "bit value (autoIncrement: 1) | (primaryKey: 2) | (unique: 4) | (notNull: 8) | (nameDerived: 16); nameDerived is set while the dictionaries filled the name",
"type": "integer"
},
"logicalName": {
"description": "The name the logical view shows; absent means none",
"type": "string"
},
"domainId": {
"description": "Id of the domain in domainEntities that governs the data type; absent means none",
"type": "string"
}
},
"required": ["id", "tableId", "options"],
"additionalProperties": false
}
},
"relationshipEntities": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"relationshipType": {
"description": "bit value (ZeroOne: 2) | (ZeroN: 4) | (OneOnly: 8) | (OneN: 16)",
"type": "integer"
},
"onDelete": {
"description": "bit value (none: 1) | (noAction: 2) | (cascade: 4) | (setNull: 8) | (setDefault: 16) | (restrict: 32); none, the default, writes no ON DELETE clause",
"type": "integer"
},
"onUpdate": {
"description": "bit value (none: 1) | (noAction: 2) | (cascade: 4) | (setNull: 8) | (setDefault: 16) | (restrict: 32); none, the default, writes no ON UPDATE clause",
"type": "integer"
},
"start": {
"$ref": "#/$defs/RelationshipPoint"
},
"end": {
"$ref": "#/$defs/RelationshipPoint"
}
},
"required": [
"id",
"relationshipType",
"onDelete",
"onUpdate",
"start",
"end"
],
"additionalProperties": false
}
},
"indexEntities": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"tableId": {
"type": "string"
},
"indexColumnIds": {
"type": "array",
"items": {
"type": "string"
}
},
"unique": {
"type": "boolean"
}
},
"required": ["id", "tableId", "indexColumnIds", "unique"],
"additionalProperties": false
}
},
"indexColumnEntities": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"indexId": {
"type": "string"
},
"columnId": {
"type": "string"
},
"orderType": {
"description": "bit value (ASC: 1) | (DESC: 2)",
"type": "integer"
}
},
"required": ["id", "indexId", "columnId", "orderType"],
"additionalProperties": false
}
},
"memoEntities": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"value": {
"type": "string"
},
"ui": {
"type": "object",
"properties": {
"x": {
"type": "number"
},
"y": {
"type": "number"
},
"width": {
"type": "number"
},
"height": {
"type": "number"
},
"color": {
"type": "string"
}
},
"required": ["x", "y", "width", "height"],
"additionalProperties": false
}
},
"required": ["id", "ui"],
"additionalProperties": false
}
},
"tableGroupEntities": {
"description": "Named, coloured rectangles drawn behind tables; a table joins one through its groupId. Written while a group exists; absent means none",
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"color": {
"type": "string"
},
"ui": {
"type": "object",
"properties": {
"x": {
"type": "number"
},
"y": {
"type": "number"
},
"width": {
"type": "number"
},
"height": {
"type": "number"
}
},
"required": ["x", "y", "width", "height"],
"additionalProperties": false
}
},
"required": ["id", "ui"],
"additionalProperties": false
}
},
"wordEntities": {
"description": "The words of the dictionary, the parts a logical name is composed of, each with its abbreviation in a physical name. Written while a word exists; absent means none",
"type": "object",
"properties": {
"fields": {
"const": ["id", "name", "abbreviation", "englishName", "description", "synonyms", "forbiddenWords"]
},
"rows": {
"description": "One row per entry in document order, its values in the order fields names them; values past the name are left out from the last empty one back",
"type": "array",
"items": {
"type": "array",
"prefixItems": [
{ "type": "string" },
{ "type": "string" },
{ "type": "string" },
{ "type": "string" },
{ "type": "string" },
{ "type": "string" },
{ "type": "string" }
],
"items": false,
"minItems": 2
}
}
},
"required": ["fields", "rows"],
"additionalProperties": false
},
"termEntities": {
"description": "The terms of the dictionary, logical names a column matches by its text, each with its physical name and domain id. Written while a term exists; absent means none",
"type": "object",
"properties": {
"fields": {
"const": ["id", "name", "physicalName", "domainId", "description", "synonyms"]
},
"rows": {
"description": "One row per entry in document order, its values in the order fields names them; values past the name are left out from the last empty one back",
"type": "array",
"items": {
"type": "array",
"prefixItems": [
{ "type": "string" },
{ "type": "string" },
{ "type": "string" },
{ "type": "string" },
{ "type": "string" },
{ "type": "string" }
],
"items": false,
"minItems": 2
}
}
},
"required": ["fields", "rows"],
"additionalProperties": false
},
"domainEntities": {
"description": "The domains of the dictionary, named data types a column or a term links to by id. Written while a domain exists; absent means none",
"type": "object",
"properties": {
"fields": {
"const": ["id", "name", "category", "dataType", "description"]
},
"rows": {
"description": "One row per entry in document order, its values in the order fields names them; values past the name are left out from the last empty one back",
"type": "array",
"items": {
"type": "array",
"prefixItems": [
{ "type": "string" },
{ "type": "string" },
{ "type": "string" },
{ "type": "string" },
{ "type": "string" }
],
"items": false,
"minItems": 2
}
}
},
"required": ["fields", "rows"],
"additionalProperties": false
},
"RelationshipPoint": {
"type": "object",
"properties": {
"tableId": {
"type": "string"
},
"columnIds": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": ["tableId", "columnIds"],
"additionalProperties": false
}
}
}