From 6acce7b1952b28f93d8368802b4a974ceb64929c Mon Sep 17 00:00:00 2001 From: Patrick Fust Date: Fri, 6 Mar 2026 15:21:35 +0100 Subject: [PATCH] Added format to data dictionary --- build.gradle | 4 +- .../dk/fust/docgen/model/datadict/Column.java | 3 + .../main/resources/documentation-schema.json | 4 + .../README.md | 2 + .../datadict/DataDictionaryConfiguration.java | 1 + .../datadict/DataDictionaryGenerator.java | 3 + .../DataDictionaryGeneratorSpec.groovy | 40 +-- site/index.html | 4 + site/v6/documentation-schema.json | 306 ++++++++++++++++++ 9 files changed, 346 insertions(+), 21 deletions(-) create mode 100644 site/v6/documentation-schema.json diff --git a/build.gradle b/build.gradle index 0c704ed..b399e20 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ plugins { allprojects { group = 'dk.fust.docgen' - version = '1.13.0' + version = '1.14.0' plugins.withType(JavaPlugin).whenPluginAdded { dependencies { @@ -22,7 +22,7 @@ allprojects { testImplementation project(':helpers:documentation-generator-test-utilities') testImplementation platform('org.spockframework:spock-bom:2.4-groovy-5.0') testImplementation 'org.spockframework:spock-core' - testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher:6.0.2' } tasks.withType(Test).configureEach { diff --git a/documentation-generator-api/src/main/java/dk/fust/docgen/model/datadict/Column.java b/documentation-generator-api/src/main/java/dk/fust/docgen/model/datadict/Column.java index 715d4ec..1145395 100644 --- a/documentation-generator-api/src/main/java/dk/fust/docgen/model/datadict/Column.java +++ b/documentation-generator-api/src/main/java/dk/fust/docgen/model/datadict/Column.java @@ -21,6 +21,9 @@ public class Column { @Description("Regular expression that the contain must obey. Example: ((\\d{3}[A-Z]?)|0{4})") private String regex; + @Description("Format for dates. Example: yyyy-MM-dd HH:mm:ss.SSS") + private String format; + @Description("Example on how the content may look. Could be a description as well: 'value between 0 and 1. eg 0,3333'") private String example; diff --git a/documentation-generator-api/src/main/resources/documentation-schema.json b/documentation-generator-api/src/main/resources/documentation-schema.json index 9054ac0..272825d 100644 --- a/documentation-generator-api/src/main/resources/documentation-schema.json +++ b/documentation-generator-api/src/main/resources/documentation-schema.json @@ -68,6 +68,10 @@ "type" : "string", "description" : "Example on how the content may look. Could be a description as well: 'value between 0 and 1. eg 0,3333'" }, + "format" : { + "type" : "string", + "description" : "Format for dates. Example: yyyy-MM-dd HH:mm:ss.SSS" + }, "keys" : { "type" : "string", "description" : "Is this column a part of the unique key?" diff --git a/generators/documentation-generator-data-dictionary/README.md b/generators/documentation-generator-data-dictionary/README.md index 8ad2696..f0bcbbb 100644 --- a/generators/documentation-generator-data-dictionary/README.md +++ b/generators/documentation-generator-data-dictionary/README.md @@ -25,6 +25,7 @@ To use the data dictionary generator, you must configure it with `dk.fust.docgen | columnPosition | [DataDictionaryConfigurationColumn](#dataDictionaryConfigurationColumn) | Customizing position | Export: `true`
Header: `Position`
Alignment: `RIGHT` | | columnType | [DataDictionaryConfigurationColumn](#dataDictionaryConfigurationColumn) | Customizing data type | Export: `true`
Header: `Type`
Alignment: `LEFT` | | columnMandatory | [DataDictionaryConfigurationColumn](#dataDictionaryConfigurationColumn) | Customizing mandatory | Export: `true`
Header: `Mandatory`
Alignment: `LEFT` | +| columnFormat | [DataDictionaryConfigurationColumn](#dataDictionaryConfigurationColumn) | Customizing format | Export: `false`
Header: `Format`
Alignment: `LEFT` | | columnKeys | [DataDictionaryConfigurationColumn](#dataDictionaryConfigurationColumn) | Customizing keys | Export: `true`
Header: `Keys`
Alignment: `LEFT` | | columnDescription | [DataDictionaryConfigurationColumn](#dataDictionaryConfigurationColumn) | Customizing description | Export: `true`
Header: `Description`
Alignment: `LEFT` | | columnExample | [DataDictionaryConfigurationColumn](#dataDictionaryConfigurationColumn) | Customizing example | Export: `true`
Header: `Example`
Alignment: `LEFT` | @@ -63,6 +64,7 @@ Documentation │ ├── dataType │ ├── regex │ ├── example + │ ├── format │ ├── mandatory │ ├── minimumValue │ ├── maximumValue diff --git a/generators/documentation-generator-data-dictionary/src/main/java/dk/fust/docgen/datadict/DataDictionaryConfiguration.java b/generators/documentation-generator-data-dictionary/src/main/java/dk/fust/docgen/datadict/DataDictionaryConfiguration.java index 85c9c9d..f34a5d9 100644 --- a/generators/documentation-generator-data-dictionary/src/main/java/dk/fust/docgen/datadict/DataDictionaryConfiguration.java +++ b/generators/documentation-generator-data-dictionary/src/main/java/dk/fust/docgen/datadict/DataDictionaryConfiguration.java @@ -27,6 +27,7 @@ public class DataDictionaryConfiguration extends AbstractDataDictionaryConfigura @MergeWithDefault private DataDictionaryConfigurationColumn columnDescription = new DataDictionaryConfigurationColumn(true, "Description", Alignment.LEFT); @MergeWithDefault private DataDictionaryConfigurationColumn columnExample = new DataDictionaryConfigurationColumn(true, "Example", Alignment.LEFT); @MergeWithDefault private DataDictionaryConfigurationColumn columnSchema = new DataDictionaryConfigurationColumn(false, "Schema", Alignment.LEFT); + @MergeWithDefault private DataDictionaryConfigurationColumn columnFormat = new DataDictionaryConfigurationColumn(false, "Format", Alignment.LEFT); private String schemaName = null; diff --git a/generators/documentation-generator-data-dictionary/src/main/java/dk/fust/docgen/datadict/DataDictionaryGenerator.java b/generators/documentation-generator-data-dictionary/src/main/java/dk/fust/docgen/datadict/DataDictionaryGenerator.java index ad4286c..6dcf837 100644 --- a/generators/documentation-generator-data-dictionary/src/main/java/dk/fust/docgen/datadict/DataDictionaryGenerator.java +++ b/generators/documentation-generator-data-dictionary/src/main/java/dk/fust/docgen/datadict/DataDictionaryGenerator.java @@ -64,6 +64,7 @@ private static Row createRowForColumn(Column column, long position, DataDictiona addCellIfConfigured(cells, dataDictionaryConfiguration.getColumnColumn(), column.getColumnName()); addCellIfConfigured(cells, dataDictionaryConfiguration.getColumnPosition(), position); addCellIfConfigured(cells, dataDictionaryConfiguration.getColumnType(), column.getDataType()); + addCellIfConfigured(cells, dataDictionaryConfiguration.getColumnFormat(), column.getFormat()); addCellIfConfigured(cells, dataDictionaryConfiguration.getColumnMandatory(), column.getMandatory() ? "Yes" : "No"); addCellIfConfigured(cells, dataDictionaryConfiguration.getColumnKeys(), column.getKeys()); addCellIfConfigured(cells, dataDictionaryConfiguration.getColumnDescription(), column.getColumnDescription()); @@ -113,6 +114,7 @@ private static Row createDescriptionForFileRow(DataDictionaryFile dataDictionary emptyCells += dataDictionaryConfiguration.getColumnKeys().getExport() ? 1 : 0; emptyCells += dataDictionaryConfiguration.getColumnPosition().getExport() ? 1 : 0; emptyCells += dataDictionaryConfiguration.getColumnType().getExport() ? 1 : 0; + emptyCells += dataDictionaryConfiguration.getColumnFormat().getExport() ? 1 : 0; for (int i = 0; i < emptyCells; i++) { cells.add(new Cell((String) null, true)); } @@ -134,6 +136,7 @@ private static Row createHeaderRow(DataDictionaryConfiguration dataDictionaryCon addHeaderCellIfConfigured(headerCells, dataDictionaryConfiguration.getColumnColumn()); addHeaderCellIfConfigured(headerCells, dataDictionaryConfiguration.getColumnPosition()); addHeaderCellIfConfigured(headerCells, dataDictionaryConfiguration.getColumnType()); + addHeaderCellIfConfigured(headerCells, dataDictionaryConfiguration.getColumnFormat()); addHeaderCellIfConfigured(headerCells, dataDictionaryConfiguration.getColumnMandatory()); addHeaderCellIfConfigured(headerCells, dataDictionaryConfiguration.getColumnKeys()); addHeaderCellIfConfigured(headerCells, dataDictionaryConfiguration.getColumnDescription()); diff --git a/generators/documentation-generator-data-dictionary/src/test/groovy/dk/fust/docgen/datadict/DataDictionaryGeneratorSpec.groovy b/generators/documentation-generator-data-dictionary/src/test/groovy/dk/fust/docgen/datadict/DataDictionaryGeneratorSpec.groovy index 71d22c4..d43c0cc 100644 --- a/generators/documentation-generator-data-dictionary/src/test/groovy/dk/fust/docgen/datadict/DataDictionaryGeneratorSpec.groovy +++ b/generators/documentation-generator-data-dictionary/src/test/groovy/dk/fust/docgen/datadict/DataDictionaryGeneratorSpec.groovy @@ -29,6 +29,7 @@ class DataDictionaryGeneratorSpec extends Specification { configuration.columnType.export = expType configuration.columnPosition.export = expPosition configuration.columnExample.export = expExam + configuration.columnFormat.export = expFormat Generator generator = configuration.getGenerator() @@ -43,25 +44,26 @@ class DataDictionaryGeneratorSpec extends Specification { mockTableFormatter.formatTableArgument.rows[2].cells.size() == cellSize where: - addDescFile | expFile | expDesc | expColumn | expKeys | expType | expPosition | expExam | expSchema | schemaName | cellSize | rowSize - false | true | true | true | true | true | true | true | true | 'schema' | 9 | 4 - false | true | true | true | true | true | true | true | false | null | 8 | 4 - false | false | true | true | true | true | true | true | false | null | 7 | 4 - false | false | false | true | true | true | true | true | false | null | 6 | 4 - false | false | false | false | true | true | true | true | false | null | 5 | 4 - false | false | false | false | false | true | true | true | false | null | 4 | 4 - false | false | false | false | false | false | true | true | false | null | 3 | 4 - false | false | false | false | false | false | false | true | false | null | 2 | 4 - false | false | false | false | false | false | false | false | false | null | 1 | 4 - true | true | true | true | true | true | true | true | true | 'schema' | 9 | 6 - true | true | true | true | true | true | true | true | false | null | 8 | 6 - true | false | true | true | true | true | true | true | false | null | 7 | 6 - true | false | false | true | true | true | true | true | false | null | 6 | 6 - true | false | false | false | true | true | true | true | false | null | 5 | 6 - true | false | false | false | false | true | true | true | false | null | 4 | 6 - true | false | false | false | false | false | true | true | false | null | 3 | 6 - true | false | false | false | false | false | false | true | false | null | 2 | 6 - true | false | false | false | false | false | false | false | false | null | 1 | 6 + addDescFile | expFile | expDesc | expColumn | expKeys | expType | expPosition | expFormat | expExam | expSchema | schemaName | cellSize | rowSize + false | true | true | true | true | true | true | false | true | true | 'schema' | 9 | 4 + false | true | true | true | true | true | true | false | true | false | null | 8 | 4 + false | false | true | true | true | true | true | false | true | false | null | 7 | 4 + false | false | false | true | true | true | true | false | true | false | null | 6 | 4 + false | false | false | false | true | true | true | false | true | false | null | 5 | 4 + false | false | false | false | false | true | true | false | true | false | null | 4 | 4 + false | false | false | false | false | false | true | false | true | false | null | 3 | 4 + false | false | false | false | false | false | false | false | true | false | null | 2 | 4 + false | false | false | false | false | false | false | false | false | false | null | 1 | 4 + true | true | true | true | true | true | true | false | true | true | 'schema' | 9 | 6 + true | true | true | true | true | true | true | false | true | false | null | 8 | 6 + true | false | true | true | true | true | true | false | true | false | null | 7 | 6 + true | false | false | true | true | true | true | false | true | false | null | 6 | 6 + true | false | false | false | true | true | true | false | true | false | null | 5 | 6 + true | false | false | false | false | true | true | false | true | false | null | 4 | 6 + true | false | false | false | false | false | true | false | true | false | null | 3 | 6 + true | false | false | false | false | false | false | false | true | false | null | 2 | 6 + true | false | false | false | false | false | false | false | false | false | null | 1 | 6 + true | false | false | false | false | false | false | true | false | false | null | 2 | 6 } def "read using generator configuration"() { diff --git a/site/index.html b/site/index.html index e96ccc1..8f0862d 100755 --- a/site/index.html +++ b/site/index.html @@ -69,6 +69,10 @@

The documentation files must adhere to the JSON schema

5 Documentation Generator JSON schema with options for applying collate to fields + + 6 + Added format + diff --git a/site/v6/documentation-schema.json b/site/v6/documentation-schema.json new file mode 100644 index 0000000..272825d --- /dev/null +++ b/site/v6/documentation-schema.json @@ -0,0 +1,306 @@ +{ + "$schema" : "https://json-schema.org/draft/2020-12/schema", + "$defs" : { + "Generation" : { + "type" : "object", + "properties" : { + "addCreatedAt" : { + "type" : "boolean", + "description" : "Adds `columnNameCreatedAt` column, that is populated with `now()`" + }, + "addUpdatedAt" : { + "type" : "boolean", + "description" : "Adds `columnNameUpdatedAt` column, that is populated with `now()`" + }, + "columnNameCreatedAt" : { + "type" : "string", + "description" : "If `addCreatedAt`, this will be the columnName" + }, + "columnNameUpdatedAt" : { + "type" : "string", + "description" : "If `addUpdatedAt`, this will be the columnName" + }, + "generateId" : { + "type" : "boolean", + "description" : "Automatically generate id on the form `tablename_id`" + }, + "generateIdDataType" : { + "enum" : [ "int", "int_array", "date", "data_array", "timestamptz", "timestamptz_array", "numeric", "numeric_array", "bool", "bool_array", "bigint", "bigint_array", "text", "text_array", "uuid", "uuid_array" ], + "description" : "Type of the generated id of the table" + }, + "triggerForUpdates" : { + "type" : "string", + "description" : "If this is non-empty, a trigger will be called with this name" + } + } + } + }, + "type" : "object", + "properties" : { + "dataDictionary" : { + "type" : "object", + "properties" : { + "dataDictionaryFiles" : { + "description" : "List of data dictionary files", + "type" : "array", + "items" : { + "type" : "object", + "properties" : { + "columns" : { + "description" : "The files columns", + "type" : "array", + "items" : { + "type" : "object", + "properties" : { + "columnDescription" : { + "type" : "string", + "description" : "Description of the field. May be several lines" + }, + "columnName" : { + "type" : "string", + "description" : "Column name in file" + }, + "dataType" : { + "type" : "string", + "description" : "Columns data type. Examples: varchar, varchar(200), numeric(17, 3)" + }, + "example" : { + "type" : "string", + "description" : "Example on how the content may look. Could be a description as well: 'value between 0 and 1. eg 0,3333'" + }, + "format" : { + "type" : "string", + "description" : "Format for dates. Example: yyyy-MM-dd HH:mm:ss.SSS" + }, + "keys" : { + "type" : "string", + "description" : "Is this column a part of the unique key?" + }, + "mandatory" : { + "type" : "boolean", + "description" : "If true, then the content may not be null or empty" + }, + "maximumValue" : { + "type" : "integer", + "description" : "Maximum value of the content" + }, + "minimumValue" : { + "type" : "integer", + "description" : "Minimum value of the content" + }, + "regex" : { + "type" : "string", + "description" : "Regular expression that the contain must obey. Example: ((\\d{3}[A-Z]?)|0{4})" + } + }, + "required" : [ "columnName", "dataType" ], + "description" : "The files columns" + } + }, + "fileDescription" : { + "type" : "string", + "description" : "Description of the file" + }, + "fileName" : { + "type" : "string", + "description" : "Filename for the data dictionary" + }, + "tableName" : { + "type" : "string", + "description" : "Corresponding table name" + }, + "tags" : { + "description" : "List of tags that may be used in a filter", + "type" : "array", + "items" : { + "type" : "string", + "description" : "List of tags that may be used in a filter" + } + }, + "version" : { + "type" : "string", + "description" : "Data dictionary version" + } + }, + "required" : [ "columns", "fileName", "version" ], + "description" : "List of data dictionary files" + } + } + }, + "description" : "Data dictionary" + }, + "databaseName" : { + "type" : "string" + }, + "documentationTitle" : { + "type" : "string" + }, + "generation" : { + "$ref" : "#/$defs/Generation", + "description" : "Default configuration on how the generation should appear - Can be overridden per table" + }, + "schemaName" : { + "type" : "string", + "description" : "Schema name" + }, + "tables" : { + "type" : "array", + "items" : { + "type" : "object", + "properties" : { + "comment" : { + "type" : "string", + "description" : "Comment to be added to the table" + }, + "createTableScript" : { + "type" : "string", + "description" : "Filename of sql-script-file to be generated. If left out, no files are generated" + }, + "fields" : { + "type" : "array", + "items" : { + "type" : "object", + "properties" : { + "check" : { + "description" : "Constraint on the values", + "type" : "array", + "items" : { + "type" : "string", + "description" : "Constraint on the values" + } + }, + "collate" : { + "type" : "string", + "description" : "How to collate the field. Omitted means use database default collation" + }, + "comment" : { + "type" : "string" + }, + "dataType" : { + "enum" : [ "int", "int_array", "date", "data_array", "timestamptz", "timestamptz_array", "numeric", "numeric_array", "bool", "bool_array", "bigint", "bigint_array", "text", "text_array", "uuid", "uuid_array" ], + "description" : "Data type of the column" + }, + "defaultValue" : { + "type" : "string", + "description" : "Default value when inserting in the database" + }, + "foreignKey" : { + "type" : "object", + "properties" : { + "columnName" : { + "type" : "string", + "description" : "Column name the foreign key points to. Is together with tableName" + }, + "enforceReference" : { + "type" : "boolean", + "description" : "Should the database enforce the reference?", + "default" : false + }, + "onDelete" : { + "enum" : [ "cascade", "set_null", "set_default", "no_action", "restrict" ], + "description" : "If the referenced record is deleted, what should happen?" + }, + "onUpdate" : { + "enum" : [ "cascade", "set_null", "set_default", "no_action", "restrict" ], + "description" : "If the referenced record is updated, what should happen?" + }, + "tableName" : { + "type" : "string", + "description" : "Table name the foreign key points to. Is together with columnName" + } + }, + "required" : [ "columnName", "tableName" ], + "description" : "Is this a foreign key to another table" + }, + "name" : { + "type" : "string", + "description" : "Name of the column" + }, + "nullable" : { + "type" : "boolean", + "description" : "May the field be null?", + "default" : true + }, + "primaryKey" : { + "type" : "boolean" + }, + "source" : { + "type" : "string", + "description" : "Points to another table and field. Must be on the form 'table.field'" + }, + "transformation" : { + "type" : "string", + "description" : "If the field is transformed, this is the documentation on how it's transformed" + }, + "unique" : { + "type" : "boolean" + } + }, + "required" : [ "dataType", "name" ] + } + }, + "generation" : { + "$ref" : "#/$defs/Generation", + "description" : "Configuration on how the generation should appear - Overrides the general generation on `Documentation`" + }, + "indexes" : { + "type" : "array", + "items" : { + "type" : "object", + "properties" : { + "comment" : { + "type" : "string", + "description" : "Comment to be added to the index" + }, + "fields" : { + "description" : "List of fields for the index", + "type" : "array", + "items" : { + "type" : "string", + "description" : "List of fields for the index" + } + }, + "name" : { + "type" : "string", + "description" : "Name of the index" + }, + "unique" : { + "type" : "boolean" + } + }, + "required" : [ "fields" ] + } + }, + "name" : { + "type" : "string" + }, + "tags" : { + "description" : "List of tags that may be used in a filter", + "type" : "array", + "items" : { + "type" : "string", + "description" : "List of tags that may be used in a filter" + } + }, + "views" : { + "type" : "array", + "items" : { + "type" : "object", + "properties" : { + "name" : { + "type" : "string", + "description" : "Name of the view" + }, + "sql" : { + "type" : "string", + "description" : "SQL that defines the view" + } + }, + "required" : [ "sql" ] + } + } + } + } + } + } +} \ No newline at end of file