Repository navigation
v1.1.0
npm 1.1.0 (all 14 @metaobjectsdev/* packages in lockstep), PyPI 1.1.0, NuGet 1.1.0 and
Maven Central 8.1.0. metamodelVersion moves 1.0 to 1.1. The vocabulary is additive:
a model that uses none of the new names loads as it did under 1.0, with three exceptions: a bare
extends naming an object in another package is refused in TypeScript, Python and C#, a
fractional validator.numeric @min or @max is refused in TypeScript, C# and Python (both
under Breaking below), and the Java and Python parser fixes under Fixed bring those
ports into line with TypeScript. What it generates is NOT unchanged in every port: in C#, Java, Kotlin's runtime and
Python the default for column and table names flips from the field name to snake_case, so a
1.0 estate whose columns are named like its fields must add
"naming": { "columns": "literal" } (see Breaking below). Each entry says which models it
affects. This is a MINOR because the
metamodel moved and reporting is a new feature. It also removes commands and exports (the docs
commands and the types behind them, under Removed): that break rides this MINOR by the
maintainer's ruling in ADR-0034 Amendment 9. One page walks a 1.0.x project through every step:
upgrading-1.0-to-1.1.md.
Breaking, C#, Java, Kotlin's runtime and Python: the default physical names are snake_case.
Column and table names the metadata does not give now come from one naming setting in
.metaobjects/config.json, defaulting to snake_case in every port (it was the field name in
those four). A database whose columns are named exactly like the fields adds
"naming": { "columns": "literal" }. The per-port flags that used to carry the rule
(--column-naming, the columnNaming pom arg, ObjectManager(column_naming=),
columnNamingStrategy) are removed and refused with a message naming the setting. Nothing in the
build fails if you skip this: the first failure is a query against a column that does not exist.
Upgrade every port of an estate together: a 1.1 TypeScript tool reads naming, a 1.0.x C#, Java
or Python tool silently ignores the unknown key and keeps the old column names, so two ports of
one estate disagree about the schema without any error (only a 1.0.x TypeScript tool refuses the
key). Migration: physical-naming.md. The entry is under
Changed.
Breaking, in every port: documentation is generated the way code is. Every generator,
documentation included, is an entry in the project's generator list; one command runs the
list; nothing is generated that the list does not declare. The docs commands are removed:
meta docs and meta verify --docs (TypeScript), dotnet meta docs (C#), metaobjects docs
(Python) and the metaobjects:docs goal (Java and Kotlin, 8.1.0). Each prints where its work
went and exits 2 (the Maven goal fails the build, so mvn exits 1). A gen command given a 1.0 docs configuration fails before it writes anything
rather than running and writing no documentation, and in TypeScript a project with no
metaobjects.config.ts fails meta gen with a pointer instead of having its pages written
from defaults. There is no upgrade script: docs-are-generators.md
has a section per port, written for a coding agent to apply to the config by hand. Ruling:
ADR-0034 Amendment 9, which numbers the release 1.1.0 (Maven 8.1.0) by the maintainer's
explicit decision. The entries are under Removed and Changed.
Breaking, Java and Kotlin: commit .metaobjects/.gen-state/.hashes.json. mvn metaobjects:generate now records what it writes in the same committed hash manifest the other
ports use, and decides overwrites from it instead of from the GENERATED header token alone.
An edited generated file is refused by name (it was overwritten), and a file no generator emits
any more is deleted. The first run adopts your existing generated files and tells you to commit
the manifest; commit it in every module. Migration:
jvm-codegen-hash-manifest.md. The
entry is under Changed.
What 1.1.0 is. The reporting release (FR-044): declare dimensions, measures, segments and an
object.report, and get a SQL view, a served read-only list route in every port, a generated
TanStack list hook, and a Cube data model, with @spine for rows that have no facts and
@default for an empty measure. It also carries the first slice of requirements (the gate in
every port's verify), the derived-key parity fix across the ports, and the list-hook and
nested-average fixes found by the first adopter to map real report pages onto the feature.
How much smaller the code gets. The size reduction comes in two steps, and each is its own
number. The first landed on 1.0.x: 439 lines of handler code retired. The second is reporting,
and it is a SQL reduction only: in an adopter, hand-written SQL went from 75 lines to 15 (-80%).
Total hand-written lines did not fall, so do not read it as a total line reduction.
Breaking, TypeScript, Python and C#: a bare extends no longer binds an object in another
package. It now fails with ERR_UNRESOLVED_SUPER, as Java already did and ADR-0042 requires. A
bare name binds the declaring file's own package, then the root. Qualify the reference:
extends: other::Base. The entry is under Changed (ADR-0059).
Breaking, TypeScript, C# and Python: attr.int and attr.long take whole numbers only, so a
fractional validator bound is refused. A validator.numeric declares @min and @max as
integers, and a fraction such as @min: 0.5 on a decimal or double field is now
ERR_BAD_ATTR_VALUE at load ("'@min' must be of type 'int' but got the fraction 0.5"), as Java
already refused it, so the five ports agree. 1.0.x TypeScript accepted it. Fix: write an integer
bound (@min: 0). A decimal-valued bound (for example "at least 0.01") cannot be declared in
1.1.0: that needs new metamodel vocabulary, which is 1.2 work. A whole number written 1.0
still loads, as 1. The entry is under Changed and the FR-044 report entries.
Breaking, in every port: a field.decimal crosses the API as one canonical string
(ADR-0019 Amendment 1). Every decimal a generated route sends, on an entity, a projection or a
report row (an avg, a ratio, a sum of a decimal), is a JSON string in plain notation with no
exponent and no trailing fraction zeros: 12.50 is sent "12.5", zero is "0". Before 1.1.0
each port sent its own form (TypeScript a string that kept trailing zeros, the others a number), so
a client that read a number from C#, Java, Kotlin or Python now reads a string, and TypeScript's
"12.50" is now "12.5". Display formatting, such as two digits
for an amount of money, is a view's job, never the wire's. On input a route takes a string in
JSON-number grammar or a JSON number, read exactly (in TypeScript a JSON number is exact to 15 significant
digits, so send a string for more); anything else is 400 validation, and so is
a value with more fraction digits than @scale or more integer digits than
@precision - @scale (nothing is rounded). A decimal filter operand uses the same grammar, is
compared exactly, and a bad one is 400 invalid_filter_value. Postgres and MySQL keep the
declared precision; SQLite and D1, which have no decimal type, keep 15 significant digits, and
meta migrate warns for a decimal there declared with @precision above 15. An ejected routes
generator keeps its old decimal handling until you resync it. The per-port entries are under
Changed.
Eleven diffs to expect when you upgrade.
-
Generated files no generator emits any more are deleted. The first full
genafter the
upgrade, in every port, deletes a file the committed hash manifest records writing, that no
generator emitted in that run and that still hashes to what was recorded (a renamed value
object's old file, an api-docs page that moved). An edited such file is refused by name and
kept. Review the deletions in the diff. The entry is under Fixed. -
An inherited reference means what it meant where it was written (ADR-0059 Decisions 3
and 7). A reference an object inherits throughextendsresolves in the package of the
node that declares it, not the inheriting object's package. A model whose base and subtype
live in different packages and that relied on a bare name meaning the subtype package's
object now binds the one in the base's package (or the root-level one). Qualify the
reference if you meant the other. -
References are written fully qualified (ADR-0059).
meta exportand canonical
serialization write every reference aspkg::Name, a root-level target referenced from a
package as::Name, and a model that spans packages with apackageon each top-level object.
Exported JSON now loads back to the same model. The neutral template data'stargetRefcarries
the same canonical value (rel product -> shop::Product), so a Mustache template that prints it
changes. Documentation pages and error messages still quote a reference as you wrote it.meta fmtstill writes references as you wrote them. Regenerate, then review the diff. -
An ejected generator needs a resync (G11). An owned copy keeps the gate and the options it
was copied with, so it does not receive the new report behaviour until you resync it. The
entries under Added and Fixed name the command for each affected generator (meta eject hooks --force,meta eject routes --force,meta eject routes-hono --force). A generator you
never ejected needs nothing. -
An ejected Java Spring generator keeps its old rules until you re-eject it. A copy of
routes,dto,repositoryorvalue-objectmade before 1.1.0 compiles after the upgrade
wherever it compiled before, and applies the rules it was copied with: it calls its own sibling
copies, and the fourAutoSetSupportselectors it calls on the packaged class are still there,
marked@Deprecated. A copy ofroutes,dtoorvalue-objectejected alone did not compile
before 1.1.0, and the upgrade does not change that. Run
mvn metaobjects:eject -Dnames=<generator> -Dforce=truefor each one you own to get a copy
that compiles alone and reads the shared rules fromSpringGeneratorSupport(the copy of it
written beside them is yours too), and merge your own edits back fromgit diff. Code of your
own that calls a static helper on the packagedSpringDtoGeneratoror
SpringRepositoryGenerator, or subclasses one of them, still compiles too: the 1.0.x helpers
are still there, marked@Deprecated, and forward toSpringGeneratorSupport. A generator you
never ejected needs nothing. -
Decimal handling is generated. Every port's generated routes gain their decimal
wire code (the canonical writer, the strict reader and the exact filter operand), and the
allowlists gain the decimal field set. An ejected routes or allowlist generator needs a
resync to get it; the Changed entries name the files per port. -
C# array properties are
IList<T>. A generated scalar or enum array property was
ICollection<T>, which EF Core 8 cannot read on SQLite; code that assigns aHashSet<T>to
one assigns aList<T>. The entry is under Changed. -
A keyless projection regenerates differently (G12).
meta genrewrites the read-only
surface of a keyless projection (no/:idroute, no by-id function, and no write verbs in the
API docs), andmeta verify --codegenreports the affected pages as stale until they are
regenerated. Runmeta genand review the diff; three-way merge preserves hand edits. -
A multi-hop enum field references the shared enum. A field that reaches a
package-level abstract enum through another field, with no@valuesor@intValueMap
redeclared on the way, used to get an enum type of its own; it now references the shared one,
in every port. In Kotlin its former<Object><Field>enum file is no longer written, and code
that imported that type imports the shared enum instead. Java has two more diffs: a
value-object field that reaches a shared or@providedenum, even in one hop, references that
type instead of nesting a copy (TicketPayload.Prioritybecomes the top-levelPriority),
and an inline enum that redeclares@valuesor@intValueMapunder a shared enum moves from
the shared enum's name to<Owner><Field>(TaskDto.PrioritybecomesTaskDto.TaskPhase).
Every other inline enum, in every port, keeps its previous name and bytes. Two build
settings follow from it. Java:SpringDtoGeneratorowns the shared enum files, so a pom
that runs the value-object or output-parser generator WITHOUT it, on a model where one of
their objects reaches a shared enum, must setemitSharedEnums=true(an<args>entry on the
SpringValueObjectGeneratororSpringOutputParserGenerator<generator>) on one of them. Kotlin:
every generator that types an enum now needsprovidedEnumNamespace/
providedEnumPackagesfor a model with a@providedenum; set them in the plugin's
<globals>. An owned (ejected) Kotlin generator keeps compiling and keeps its previous
@providedanswer until you re-eject it. An owned Javavalue-objectoroutput-parser
generator must be re-ejected, or merged with its new reference, when a response value object
reaches a shared or@providedenum: an old copy of one beside the packaged other generates
code that does not compile. The Fixed entry lists each port's before and after, and the
re-eject commands. -
CLI exit codes changed.
meta genon a model that does not load exits 1 (1.0.13 exited 2).
meta initin an initialised project is a no-op that exits 0 (it exited 1;--forcestill
re-scaffolds). The removed docs commands exit 2, except the Mavendocsgoal, which fails
the build, somvnexits 1. A script that tests for a specific code needs the new one. -
Smaller changes an adopter can hit. Each has its own entry.
- TypeScript:
ObjectManagernow enforces numeric bounds, array bounds, uri/inet format and
an assigned primary key;RequirementTestArgsandRequirementViewgained required
fields (a compile break for code that builds them by hand). - Java: every regenerated class has a one-time header diff;
entityno longer writes
<Name>Extractor; decimal filter operands areBigDecimal, notString, so a hand-written
repository that casts(String) p.value()breaks. - Kotlin: also emits
MetaPortableColumnTypes.ktand<Report>Names;portableUuidbinds
text on MySQL and SQLite, which differs from an Exposed-createdBINARY(16)column. - Python: refuses a project module that shadows the standard library; answers 400, not 422,
for a malformed body. - The
mermaid-ergenerator is removed. - C# and Python:
genandverify --codegenneed a generator list (codegen/Generators.cs,
written bydotnet meta init;metaobjects.config.yaml), and exit 2 without one. Python's
gen <dir> --outform is gone.
- TypeScript:
Not in 1.1.0. Derived measures, the preview reporting library, the dbt exporter, the second
requirements slice and the advisory lint port, the JSON Schema and OpenAPI generators, the
generator catalog and the Atlas evaluation are 1.2 work.
The complete 1.1.0 entry (Added, Changed, Deprecated, Removed, Fixed) is in CHANGELOG.md; it is too long for a release body.