|
| 1 | +# Migrating `0.x` → `1.0` (Metamodel 1.0) |
| 2 | + |
| 3 | +This guide consolidates every breaking change an adopter absorbs moving from the |
| 4 | +`0.x` / `7.x` line to the **1.0 stable** release (Metamodel 1.0). Most of these |
| 5 | +already shipped incrementally across `0.14`–`0.15`; the 1.0 cut is the moment to be |
| 6 | +on all of them. The stability promise that begins at 1.0 is the |
| 7 | +[compatibility policy](../../compatibility-policy.md). |
| 8 | + |
| 9 | +## 0. Update the dependency version |
| 10 | + |
| 11 | +Package versions **re-baseline** at the cut (both forward — see |
| 12 | +[ADR-0035 §2](../../../spec/decisions/ADR-0035-one-zero-stability-commitment-and-version-unification.md)): |
| 13 | + |
| 14 | +| Ecosystem | From | To | |
| 15 | +|---|---|---| |
| 16 | +| npm / PyPI / NuGet | `0.15.x` | **`1.0.0`** | |
| 17 | +| Maven Central (Java / Kotlin) | `7.7.x` | **`8.0.0`** | |
| 18 | + |
| 19 | +All ports at these versions implement **Metamodel 1.0**. There is no `1.0`–`7.x` |
| 20 | +overlap: the lines are independent and each only moves forward. |
| 21 | + |
| 22 | +## 1. `verify` is strict-by-default (shipped 0.14.0) |
| 23 | + |
| 24 | +`verify` now **fails** on unknown types / subtypes / attributes / children across all |
| 25 | +CLI ports, rather than silently passing. |
| 26 | + |
| 27 | +- **If the gate now fails on your metadata:** the offending attr/child is not a |
| 28 | + registered metamodel member. Either correct it, or — for genuinely author-supplied |
| 29 | + properties — move it into the registered `attr.properties` bag (exempt from the |
| 30 | + strict-attr check). Errors name the exit: `ERR_UNKNOWN_ATTR` / |
| 31 | + `ERR_CHILD_NOT_ALLOWED` / `ERR_UNKNOWN_TYPE`. |
| 32 | +- **Escape hatch** (per port): `meta verify --lax` (TS), `metaobjects verify --lax` |
| 33 | + (Python), `dotnet meta verify --lax` (C#), `-Dmeta.lax=true` (Java/Kotlin Maven). |
| 34 | + `gen`/`docs` stay lax by default; the Java goals gate at generate-time too. |
| 35 | + |
| 36 | +## 2. A jsonb open-bag is a parsed JSON value (shipped 0.14.0) |
| 37 | + |
| 38 | +A `field.string` + `@dbColumnType: jsonb` now surfaces a **parsed JSON value** at the |
| 39 | +API boundary (TS `z.unknown()`, Python `Any`, Java/Kotlin/C# the native map/node), |
| 40 | +not a JSON string. The stored/wire form is unchanged. |
| 41 | + |
| 42 | +- **Migration:** consumers that received a string and called `JSON.parse(...)` (or the |
| 43 | + per-port equivalent) must drop that parse — the value arrives already parsed. |
| 44 | + |
| 45 | +## 3. `field.timestamp` is instant-by-default (shipped 0.15.0) |
| 46 | + |
| 47 | +`field.timestamp` now maps to an **instant** (`timestamptz` / `Instant` / |
| 48 | +`DateTimeOffset` / timezone-aware `datetime`) by default. |
| 49 | + |
| 50 | +- **To keep the old naive/local behavior:** add **`@localTime: true`** to the field. |
| 51 | +- **Retired:** `@dbColumnType: timestamp_with_tz` — the timezone-awareness is now |
| 52 | + derived from the subtype, so remove that escape. |
| 53 | + |
| 54 | +```jsonc |
| 55 | +// before (0.14): // after (1.0): |
| 56 | +{ "field.timestamp": { { "field.timestamp": { |
| 57 | + "name": "createdAt", "name": "createdAt" }} // instant by default |
| 58 | + "@dbColumnType": "timestamp_with_tz" |
| 59 | +}} // ...or naive: add "@localTime": true |
| 60 | +``` |
| 61 | + |
| 62 | +## 4. `@dbColumnType` slim-and-derive (shipped 0.15.0) |
| 63 | + |
| 64 | +`@dbColumnType` narrows to genuinely-physical escapes. **Array-ness is derived** from |
| 65 | +`isArray`, and the `*_array` column types (`uuid_array`, `text_array`) plus `@kind: |
| 66 | +text` are **dropped**. |
| 67 | + |
| 68 | +- **Migration:** remove any `@dbColumnType: *_array` / `@kind: text`; use the field |
| 69 | + subtype + `isArray` (arrays derive their column type automatically). |
| 70 | + |
| 71 | +## 5. `index.*` type + `identity.secondary` key-purity (shipped 0.15.1) |
| 72 | + |
| 73 | +`@unique` is **removed** from `identity.secondary` (now inherently a *unique* key → |
| 74 | +a legacy `@unique` fails load with `ERR_UNKNOWN_ATTR`). A non-unique index moves to |
| 75 | +the new **`index.lookup`** type. |
| 76 | + |
| 77 | +- **Full mechanical rewrite + the no-DDL-churn guarantee:** |
| 78 | + [identity.secondary → index.lookup](identity-secondary-to-index-lookup.md). |
| 79 | + |
| 80 | +## 6. Deprecated `codegen-ts/generators` export removed (at the 1.0 cut) |
| 81 | + |
| 82 | +Importing the built-in generators from `@metaobjectsdev/codegen-ts/generators` |
| 83 | +(`entityFile` / `queriesFile` / `routesFile` / `barrel`) is **removed** at 1.0. |
| 84 | + |
| 85 | +- **Migration:** import the owned copies `meta init` scaffolds into |
| 86 | + `codegen/generators/*` and wire those in `metaobjects.config.ts`. See |
| 87 | + [own-your-codegen](../own-your-codegen.md). (If you scaffolded with a recent |
| 88 | + `meta init`, you already import the owned copies — no change needed.) |
| 89 | + |
| 90 | +## Additive in 1.0 (no migration required) |
| 91 | + |
| 92 | +- **`field.uri` / `field.inet` subtypes + `@stringFormat`** (`email` / `hostname`) |
| 93 | + for validated-string content — new, opt-in. Adopt where useful. |
| 94 | +- **Reverse navigation** via generated explicit FK finders — additive. |
| 95 | +- **`field.enum`, `index.lookup`, currency, M:N relationships** — all available. |
| 96 | + |
| 97 | +## Not in 1.0: the declared-API surface (FR-024) |
| 98 | + |
| 99 | +`api.*` / `operation.*` / `binding.*` are **deferred** post-1.0 (reserved but |
| 100 | +unregistered). Nothing to migrate; they can be added later without a breaking change. |
| 101 | +Derived CRUD remains the zero-config default. (Tracked in #10.) |
0 commit comments