JSON interchange format
The current JSON version optionally carries target generation objects and hooks arrays on models, schemas, and
tables. Older documents omit these fields and receive default settings and empty hook lists.
bluep export json <dir> writes the whole model as one JSON document; add --resolved to inline effective library
objects with a resolved_sources provenance map. bluep import json <file> --out <dir> reads
it back. The document is canonical: object keys are sorted, indentation is two spaces, no timestamps or
absolute paths appear, so exporting the same model twice gives identical bytes.
Shape
- The root object carries the format version (an integer, currently 6) and one key per model section
(
metadata,naming,lint,domains,enums,glossary,entities,relationships,many_to_many,hierarchies,subject_areas,targets,property_defs,classifications). - Every model type is a JSON object whose keys are the Rust field names in
snake_case. - Maps (
BTreeMap<Name, _>) are JSON objects keyed by the element name, with sorted keys. - Ordered collections (attributes, columns, key columns, enum values) are JSON arrays in declaration order.
- Enumerations (
DialectId,RefAction, cardinalities,CaseStyle,Severity,IdentityMode) are lowercase strings as written in the text format (set_null,zero_or_one,by_default). - Logical types are objects with a
kinddiscriminator and the type's parameters; physical types are objects withname,args,modifiersandarray. - Defaults are objects with a
kindofnull,bool,number,stringorexprand avalue. - Source positions (
Origin) are omitted. Missing optional keys are read asNone/defaults.
A reader must accept every version up to the current one and treat missing keys as defaults.
Properties and classifications
Version 2 adds model-level property_defs and classifications maps. Property definitions carry a name,
type, optional description and default, applicable object kinds, and a required flag. Choice properties also
carry choices. Classifications carry a name, optional description, ordered levels, and required and
inherit flags. Objects with metadata emit properties as values of JSON string, integer, boolean, or
string-array type, and classifications as level strings; empty maps are omitted from objects.
Version 3
Version 3 adds procedural and security objects. Readers accept versions 1 to 3; keys missing from older documents are read as defaults (no routines, triggers, materialized views, partitioning, roles or grants).
targets.*.roles: an object keyed by role name; each role is{"name", "login", "member_of": [..], "options": {..}}.schemas.*.routines: an object keyed by routine name; each routine is{"name", "kind" ("function" | "procedure"), "args": [{"name"?, "type" (physical type), "mode" ("in" | "out" | "inout"), "default"?}], "returns"?, "language"?, "body", "options": {..}, "comment"?, "properties"?}.schemas.*.materialized_views: an object keyed by name; each is{"name", "sql", "with_data", "indexes" (as for tables), "comment"?, "properties"?}.schemas.*.grants: an array in declaration order; each grant is{"privileges": [..], "object": {"kind" ("schema" | "all_tables" | "all_sequences" | "all_routines" | "table" | "view" | "sequence" | "routine"), "name"?}, "grantee", "with_grant_option"}.tables.*.triggers: an object keyed by trigger name; each is{"name", "timing" ("before" | "after" | "instead_of"), "events": [..], "update_columns": [..], "level" ("row" | "statement"), "when"?, "function"?, "body"?, "comment"?}.tables.*.partitioning:nullor{"method" ("range" | "list" | "hash"), "columns": [index columns], "partitions": [{"name", "bound"}]}.
Optional fields (?) are omitted when absent, like a column's comment; options maps are always written,
like a table's options. Table indexes are read back on import as well.
Version 4
Version 4 adds lossless reverse-engineering fields. Targets may contain extensions; schemas may contain
collations; and tables may contain exclusion_constraints and policies. Columns carry optional generated
definitions and option maps. Identities include min_value, max_value, cache, and cycle; indexes include
kind, options, and comments. Constraint, sequence, and enum comments are represented as optional strings.
Readers accept versions 1 to 4 and use ordinary defaults when these keys are absent.
Version 5
Version 5 accompanies the bluep rename. Readers accept versions 1 to 5; version 4 documents remain valid and missing keys continue to use ordinary defaults.
Version 6
Version 7 adds the root many_to_many object and optional inferred evidence on relationships. Association ends
contain an entity, optional key, ordered column pairs, and a required flag. Evidence objects contain kind,
reason, and confidence. Versions 1 through 6 default associations and evidence to empty values.
Version 6 adds generalization hierarchies. The root hierarchies array preserves declaration order for subtype
names and discriminator values while hierarchy names remain canonical. Each hierarchy includes name, supertype,
an optional discriminator, category, subtypes, discriminator_values, and optional description and
properties. Each target's hierarchy_transformations object maps hierarchy names to identity, rolldown, or
rollup; empty maps and identity defaults are accepted. Readers accept versions 1 to 7, with empty hierarchy maps
when these keys are absent from versions 1 to 5.
The key inventory below is generated by the test json_doc_is_current from the commerce sample and is
rewritten with BLUEP_UPDATE_GOLDEN=1 cargo test -p bluep-core --test docs_current.
Key inventory (commerce sample)
Generated from json_model::to_json of the commerce sample. * stands for a map key and [] for an array element; the second column lists the JSON types observed at the path.
| path | types |
|---|---|
| classifications | object |
| domains.*.check | string |
| domains.*.default.kind | string |
| domains.*.default.value | string |
| domains.*.description | string |
| domains.*.name | string |
| domains.*.nullable | boolean |
| domains.*.physical | object |
| domains.*.ty.kind | string |
| domains.*.ty.max_len | integer |
| domains.*.ty.precision | integer |
| domains.*.ty.scale | integer |
| entities.*.attributes[].default.kind | string |
| entities.*.attributes[].default.value | boolean, string |
| entities.*.attributes[].name | string |
| entities.*.attributes[].nullable | boolean |
| entities.*.attributes[].terms | array |
| entities.*.attributes[].ty.kind | string |
| entities.*.attributes[].ty.len | integer |
| entities.*.attributes[].ty.max_len | integer |
| entities.*.attributes[].ty.name | string |
| entities.*.description | string |
| entities.*.name | string |
| entities.*.primary_key.attributes[] | string |
| entities.*.primary_key.name | string |
| entities.*.tags | array |
| entities.*.terms | array |
| entities.*.terms[] | string |
| entities.*.unique_keys | object |
| entities..unique_keys..attributes[] | string |
| entities..unique_keys..name | string |
| enums.*.name | string |
| enums.*.values[] | string |
| glossary.*.aliases | array |
| glossary.*.aliases[] | string |
| glossary.*.definition | string |
| glossary.*.name | string |
| lint.rules.* | string |
| metadata.description | string |
| metadata.name | string |
| metadata.properties | object |
| metadata.version | string |
| naming.rules.*.case | string |
| naming.rules.*.forbidden | array |
| naming.rules.*.max_length | integer |
| naming.rules.*.prefix | string |
| property_defs | object |
| relationships.*.child | string |
| relationships.*.child_cardinality | string |
| relationships.*.description | string |
| relationships.*.identifying | boolean |
| relationships.*.name | string |
| relationships.*.on_delete | string |
| relationships.*.on_update | string |
| relationships.*.pairs[].child | string |
| relationships.*.pairs[].parent | string |
| relationships.*.parent | string |
| relationships.*.parent_cardinality | string |
| subject_areas.*.description | string |
| subject_areas.*.entities[] | string |
| subject_areas.*.layout | object |
| subject_areas..layout..x | integer |
| subject_areas..layout..y | integer |
| subject_areas.*.name | string |
| subject_areas.*.notation | string |
| targets.*.dialect | string |
| targets.*.name | string |
| targets.*.roles | object |
| targets.*.roles.app_rw.login | boolean |
| targets.*.roles.app_rw.member_of | array |
| targets.*.roles.app_rw.name | string |
| targets.*.roles.app_rw.options | object |
| targets..schemas..enums.*.name | string |
| targets..schemas..enums.*.values[] | string |
| targets..schemas..grants | array |
| targets..schemas..grants[].grantee | string |
| targets..schemas..grants[].object.kind | string |
| targets..schemas..grants[].object.name | string |
| targets..schemas..grants[].privileges[] | string |
| targets..schemas..grants[].with_grant_option | boolean |
| targets..schemas..materialized_views | object |
| targets..schemas..materialized_views.mv_daily_sales.indexes.*.columns[].column | string |
| targets..schemas..materialized_views.mv_daily_sales.indexes.*.columns[].descending | boolean |
| targets..schemas..materialized_views.mv_daily_sales.indexes.*.include | array |
| targets..schemas..materialized_views.mv_daily_sales.indexes.*.name | string |
| targets..schemas..materialized_views.mv_daily_sales.indexes.*.unique | boolean |
| targets..schemas..materialized_views.mv_daily_sales.name | string |
| targets..schemas..materialized_views.mv_daily_sales.sql | string |
| targets..schemas..materialized_views.mv_daily_sales.with_data | boolean |
| targets..schemas..name | string |
| targets..schemas..routines | object |
| targets..schemas..routines.set_updated_at.args | array |
| targets..schemas..routines.set_updated_at.body | string |
| targets..schemas..routines.set_updated_at.kind | string |
| targets..schemas..routines.set_updated_at.language | string |
| targets..schemas..routines.set_updated_at.name | string |
| targets..schemas..routines.set_updated_at.options | object |
| targets..schemas..routines.set_updated_at.returns | string |
| targets..schemas..sequences | object |
| targets..schemas..sequences.*.cycle | boolean |
| targets..schemas..sequences.*.increment | integer |
| targets..schemas..sequences.*.name | string |
| targets..schemas..sequences.*.start | integer |
| targets..schemas..tables.*.check_constraints | object |
| targets..schemas..tables..check_constraints..expr | string |
| targets..schemas..tables..check_constraints..name | string |
| targets..schemas..tables.*.columns[].attribute | string |
| targets..schemas..tables.*.columns[].default.kind | string |
| targets..schemas..tables.*.columns[].default.value | boolean, string |
| targets..schemas..tables.*.columns[].identity.mode | string |
| targets..schemas..tables.*.columns[].name | string |
| targets..schemas..tables.*.columns[].nullable | boolean |
| targets..schemas..tables.*.columns[].ty.args | array |
| targets..schemas..tables.*.columns[].ty.args[] | integer |
| targets..schemas..tables.*.columns[].ty.array | boolean |
| targets..schemas..tables.*.columns[].ty.modifiers | array |
| targets..schemas..tables.*.columns[].ty.modifiers[] | string |
| targets..schemas..tables.*.columns[].ty.name | string |
| targets..schemas..tables.*.comment | string |
| targets..schemas..tables.*.entity | string |
| targets..schemas..tables.*.foreign_keys | object |
| targets..schemas..tables..foreign_keys..columns[] | string |
| targets..schemas..tables..foreign_keys..deferrable | boolean |
| targets..schemas..tables..foreign_keys..name | string |
| targets..schemas..tables..foreign_keys..on_delete | string |
| targets..schemas..tables..foreign_keys..on_update | string |
| targets..schemas..tables..foreign_keys..ref_columns[] | string |
| targets..schemas..tables..foreign_keys..ref_table | string |
| targets..schemas..tables..foreign_keys..relationship | string |
| targets..schemas..tables.*.indexes | object |
| targets..schemas..tables..indexes..columns[].column | string |
| targets..schemas..tables..indexes..columns[].descending | boolean |
| targets..schemas..tables..indexes..include | array |
| targets..schemas..tables..indexes..name | string |
| targets..schemas..tables..indexes..unique | boolean |
| targets..schemas..tables.*.name | string |
| targets..schemas..tables.*.options | object |
| targets..schemas..tables.*.partitioning | null |
| targets..schemas..tables.*.primary_key.columns[] | string |
| targets..schemas..tables.*.primary_key.name | string |
| targets..schemas..tables.*.triggers | object |
| targets..schemas..tables.*.triggers.trg_order_touch.events[] | string |
| targets..schemas..tables.*.triggers.trg_order_touch.function | string |
| targets..schemas..tables.*.triggers.trg_order_touch.level | string |
| targets..schemas..tables.*.triggers.trg_order_touch.name | string |
| targets..schemas..tables.*.triggers.trg_order_touch.timing | string |
| targets..schemas..tables.*.triggers.trg_order_touch.update_columns | array |
| targets..schemas..tables.*.unique_constraints | object |
| targets..schemas..tables..unique_constraints..columns[] | string |
| targets..schemas..tables..unique_constraints..name | string |
| targets..schemas..views | object |
| targets..schemas..views.*.comment | string |
| targets..schemas..views.*.name | string |
| targets..schemas..views.*.sql | string |
| version | integer |