Skip to content

Commit 0254dc7

Browse files
committed
Merge remote-tracking branch 'origin/main' into fm/mo-deps-p2-s6
# Conflicts: # CHANGELOG.md # docs/CONFORMANCE.md # docs/features/metadata-dependencies.md # fixtures/dependency-conformance/README.md
2 parents a0131df + a50b9f2 commit 0254dc7

469 files changed

Lines changed: 17581 additions & 773 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎AGENTS.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ PyPI has had no product change since `0.25.0` — nothing is broken.
7171
- **Kotlin** — `codegen-kotlin` (KotlinPoet on JVM): entity + Exposed table + Spring controller + payload + relations + filter allowlist + validator + stored-proc + output-parser generators. `integration-tests-kotlin` runs the persistence-conformance corpus through Exposed against Testcontainers Postgres.
7272

7373
**Cross-port conformance corpora** (every port runs the shared corpus):
74-
- Metamodel: `fixtures/conformance/` (413 fixtures; 32 shared corpora in total — per-corpus counts + the corpus x port matrix live in `docs/CONFORMANCE.md`). TS / C# / Java / Python all green.
74+
- Metamodel: `fixtures/conformance/` (413 fixtures; 34 shared corpora in total — per-corpus counts + the corpus x port matrix live in `docs/CONFORMANCE.md`). TS / C# / Java / Python all green.
7575
- Render: `fixtures/render-conformance/`. TS / C# / Java / Kotlin / Python byte-identical.
7676
- Persistence: `fixtures/persistence-conformance/`. **Query** scenarios run on every port (TS / C# / Java / Kotlin / Python), each provisioning its test DB by executing the committed, TS-produced `canonical/schema.postgres.sql` (Postgres only — Derby dropped for the cross-port query corpus, ADR-0015; the FR-044 `report-*` scenarios also run on SQLite, MySQL and D1 where a port has the engine, see [docs/CONFORMANCE.md](docs/CONFORMANCE.md)). The **migration** scenarios are exercised by **TS only** (TS owns schema migrations). **The corpus now gates WRITES, not just reads (SP-H):** an `op: roundtrip` scenario type INSERTs through each port's runtime/ORM write codec (NOT raw SQL), reads the row back, and asserts the wire-normalized value. The `AllTypes` entity (`roundtrip-all-types.yaml`) carries one field of **every** persistable `field.*` subtype — string/int/long/double/float/decimal/boolean/date/time/timestamp(+tz)/currency/enum/uuid/object — plus an **array-of-VO** `field.object @isArray @storage:jsonb` column (`labels`, written as 2-element / empty-`[]` / single-element arrays across the three rows) — so every subtype write+read (incl. the array-of-value-object jsonb codec) round-trips through every port against Testcontainers PG. (`field.byte`/`field.short`/`field.class` were cut as non-functional registration-only stubs — the matrix tracks only genuinely-supported subtypes; see `fixtures/registry-conformance/README.md` → "Per-subtype write-round-trip matrix".)
7777
- API-contract: `fixtures/api-contract-conformance/`. TS / C# / Java / Kotlin / Python all green — each port runs **two lanes**: a hand-rolled reference server AND its **generated** API artifact booted over HTTP (the deployed controller/routes; TS+C# full-stack vs Testcontainers PG, Java/Kotlin/Python generated controller + in-memory repo behind the consumer seam). The generated fan-out found 10 real deployment bugs golden snapshots missed. Three sub-corpora run the **generated lane only, on all five ports** — `write-through/`, `projection/` (F22: a view-only `object.projection` serves GET list + GET by id and answers every write verb with `405 {"error": "method_not_allowed"}`) and `report/` (FR-044: a view-backed `object.report` serves GET list, answers `POST` with that same `405`, and mounts no `/{id}` route). That is deliberate, not a gap: what is under test is whether a port's GENERATOR emits those routes, and a hand-rolled reference server would answer every scenario by construction. The `m2m/` sub-corpus also gates **TPH x M:N together** (base-declared, subtype-declared, abstract-mid-declared, a non-subtype source onto a subtype TARGET, and the cross-subtype source id answering `200 []`) — the two corpora were originally built disjoint (`tph/` had no relationships, `m2m/` no discriminators), which is precisely how that defect class survived.

‎CHANGELOG.md‎

Lines changed: 173 additions & 1 deletion
Large diffs are not rendered by default.

‎README.md‎

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,20 @@ npx meta eject entity queries names barrel # copy them in; add the lin
4040
npx meta gen && npx meta verify --codegen # generate, then fail if generated code has drifted
4141
```
4242

43+
The generated TypeScript imports `drizzle-orm`, `zod`, `fastify` and a database driver, which
44+
`npm` does not add for you. This pair installs everything the stock `entity`, `queries` and `routes`
45+
output needs to compile (SQLite shown; swap in `pg` and `@types/pg` for Postgres):
46+
47+
```bash
48+
npm i -D @metaobjectsdev/cli @metaobjectsdev/codegen-ts @metaobjectsdev/metadata typescript @types/better-sqlite3
49+
npm i @metaobjectsdev/runtime-ts drizzle-orm zod fastify better-sqlite3
50+
```
51+
52+
Expect to write generators of your own. The reference ones cover the common cases, and a
53+
generator you own (`npx meta generator new <name>`) is regenerated on every model change and
54+
gated by `meta verify --codegen`, which is what keeps output from drifting. See
55+
[write your own generator](docs/recipes/write-your-own-generator.md).
56+
4357
Java, Kotlin, C# and Python start the same way from their own package: see
4458
[`docs/ports/`](docs/ports/).
4559

@@ -166,12 +180,13 @@ first-week wedge plan — and `meta init` picks up from there.
166180
| Payload-VO codegen (the value object's own type, ADR-0056) | Yes (`entityFile()`) | Yes (`SpringValueObjectGenerator`) | Yes (`KotlinEntityGenerator`) | Yes (`EntityGenerator`) | Yes (`entity`) |
167181
| Migration emission | `meta migrate` (Postgres / SQLite / D1) | Via TS toolchain (`@metaobjectsdev/cli migrate`) | Via TS toolchain (`@metaobjectsdev/cli migrate`) | Via TS toolchain (ADR-0015) | Via TS toolchain (ADR-0015) |
168182
| DB-drift verify | `meta verify --db <url>` | Template-drift: `Verify.check`; schema-drift is TS-owned (ADR-0015) | Template-drift: `Verify.check`; startup: `MetadataStartupValidator` | `dotnet meta verify` (codegen-drift) | Schema-drift is TS-owned (ADR-0015) |
183+
| Prisma schema (`orm: "prisma"`, #479) | `prismaSchemaFile()` writes `schema.prisma` (Postgres / MySQL / SQLite); `verify --codegen` and `verify --db` gate it | No | No | No | No |
169184
| Template-drift verify | Yes | Yes (`Verify.check`) | Yes (via Java) | Yes (`dotnet meta verify`) | Yes (`metaobjects.render.verify`) |
170185
| YAML authoring (sigil-free → JSON) | Yes | Yes | Yes (via Java) | Yes | Yes |
171186
| Capability requirements (`requirement.*`) | `meta verify` gate + authoring lint; `requirementTests()` stubs | `mvn metaobjects:verify` gate; JUnit Jupiter `requirement-tests` | Gate via the Java Maven goal; JUnit Jupiter `requirement-tests` | `dotnet meta verify` gate; xUnit `requirement-tests` | `metaobjects verify` gate; pytest `requirement-tests` |
172187
| Reporting vocabulary (`dimension` / `measure` / `segment` / `object.report`, FR-044) | Registered; a view-backed report becomes a SQL view in `meta migrate`, is read by `ObjectManager`, and gets generated read-only list routes and a TanStack list hook (no grid or form); the `cube-model` generator writes the vocabulary as Cube data-model files | Registered; OMDB reads a view-backed report; generates a read-only Spring controller, DTO, repository and filter allowlist | Registered (via Java); generates an Exposed table object, a row data class, a filter allowlist and a read-only Spring controller per view-backed report | Registered; generates a keyless EF Core row type, read-only routes and a filter allowlist per view-backed report | Registered; `ObjectManager` reads a view-backed report; generates a Pydantic row model, a read-only FastAPI router and a filter allowlist |
173188
| Libraries (`libraries: [...]`) | Yes | Yes | Yes (via Java) | Yes | Yes |
174-
| Metadata dependencies (`dependencies`) | Yes (`meta deps sync`, `path` transport) | Phase 2 | Phase 2 | Phase 2 | Yes (loads the synced snapshot) |
189+
| Metadata dependencies (`dependencies`) | Yes (`meta deps sync`: `path`, `npm` and `python` transports) | Phase 2 | Phase 2 | Phase 2 | Yes (loads the synced snapshot) |
175190
| Runtime metadata (ObjectManager-style) | Yes (`runtime-ts`) | Yes (OMDB) | Yes (via Java OMDB + Exposed) | Roadmap | Yes (ObjectManager) |
176191
| React / Angular UI client (browser) | React: **published** (`@metaobjectsdev/react` + `@metaobjectsdev/tanstack`), codegen + runtime. Angular 18: **source-only by decision** ([ADR-0048](spec/decisions/ADR-0048-angular-tier-source-only.md)) — `@metaobjectsdev/angular` + `@metaobjectsdev/codegen-ts-angular` build in-repo on their own `0.6.x` line but are deliberately not on npm (`npm i @metaobjectsdev/angular` will 404) until they meet the ADR's promotion bar. Consume them from source. | Consumes TS client via REST | Consumes TS client via REST | Consumes TS client via REST | Consumes TS client via REST |
177192
| Own a generator (`eject`) | Yes (`meta eject`) | Yes (`mvn metaobjects:eject`) | Yes (`mvn metaobjects:eject`) | Yes (`dotnet meta eject`) | Yes (`metaobjects eject`) |
@@ -261,8 +276,8 @@ sixth ships two libraries at their own stability labels:
261276
`meta eject <library>`. See [`docs/features/libraries.md`](docs/features/libraries.md).
262277

263278
**Sharing a model across your own projects** *(the TypeScript toolchain publishes;
264-
TypeScript and Python projects consume, over a `path` dependency such as a sibling
265-
checkout or submodule; Java, Kotlin and C# arrive in Phase 2)* — one project publishes
279+
TypeScript, Python, Java and Kotlin projects consume, from an installed npm or Python
280+
package or over a `path` dependency such as a sibling checkout; C# arrives in Phase 2)* — one project publishes
266281
part of its model (a common `Customer`, an audited base, a set of enums) with
267282
`sharedModelFile()`, and another declares it in `dependencies`, syncs it into a
268283
committed, hash-locked snapshot and builds on it with `extends` and references. When the

‎agent-context/skills/metaobjects-authoring/references/metadata-dependencies.md‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,16 @@ build on a shared model.** A project may declare `dependencies` in
77
`.metaobjects/config.json` and `meta deps sync` a publisher's metadata into a
88
committed snapshot — that snapshot loads BEFORE your own files, so a foreign
99
abstract resolves via `extends` and a foreign node re-opens via `overlay: true`
10-
exactly like a local one. Two rules are specific to that boundary:
10+
exactly like a local one. A dependency names one transport: `path` (a directory
11+
relative to the directory holding `.metaobjects/`), `npm` (an installed npm
12+
package, e.g. `{ "name": "acme-model", "npm": "@acme/model", "dir": "metaobjects" }`)
13+
or `python` (an installed Python package by its import name, e.g.
14+
`{ "name": "acme-model", "python": "acme_model", "dir": "metaobjects" }`). For
15+
`npm`/`python`, install the package with the project's package manager first;
16+
`meta deps sync` locates it, copies its shared model into the snapshot, and says
17+
what to install when it is missing. Prefer the package transport over a `path` into
18+
someone else's checkout when the publisher releases a package. Two rules are
19+
specific to that boundary:
1120

1221
- **Say `overlay: true` on every amendment to a node you don't own.** Within one
1322
project the parser merges a same-`(type, package::name)` redeclaration whether

‎agent-context/skills/metaobjects-codegen/SKILL.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ exact config, generator names and commands for this project; read it. The other
4444
| `references/dependencies-and-shared-models.md` | the project consumes or publishes metadata across projects |
4545
| `references/typescript-document-store.md` | a TypeScript project on MongoDB, or any store MetaObjects does not manage, wanting a tested repository generator |
4646
| `references/typescript-mysql.md` | a TypeScript project on a MySQL database |
47+
| `references/typescript-prisma.md` | a TypeScript project that keeps Prisma as its ORM |
4748
| `references/typescript-retargeting.md` | a TypeScript project on a framework other than Fastify, Hono or React |
4849
| `references/typescript-templates.md` | declarative Mustache template-codegen in a TypeScript project |
4950
| `references/typescript-docs.md` | the docs generators (`docsFile`, `apiDocsFile`, `agentDocsFile`, `requirementsFile`, `metamodelDocsFile`, `docsSiteFile`) in a TypeScript project |

‎agent-context/skills/metaobjects-codegen/references/any-stack.md‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ reference generators target React and TanStack. Anything else is this page.
3434
| Layer | Always available | When your target is not built in |
3535
|---|---|---|
3636
| **model** — types, create/PATCH validation, filter and sort allowlists | yes, in every port, for every store | — |
37-
| **persistence** — how rows are read and written | Postgres, SQLite, D1; MySQL (TypeScript, Java) | §3 |
37+
| **persistence** — how rows are read and written | Postgres, SQLite, D1; MySQL (TypeScript, Java); a Prisma schema (TypeScript) | §3 |
3838
| **api** — the HTTP surface | Fastify, Hono | §4 |
3939
| **client** — hooks, forms, grids | React, TanStack | §5 |
4040

@@ -52,6 +52,12 @@ the column-type table and the behaviour differences are in `typescript-mysql.md`
5252
OMDB's `MySQLDriver` reads and writes MySQL; the generated DTOs and controllers are
5353
dialect-neutral.
5454

55+
**Prisma as the ORM (TypeScript).** Set `orm: "prisma"` and wire `prismaSchemaFile()`. The
56+
model then writes `schema.prisma` (Postgres, MySQL, SQLite) beside Zod schemas and types, and
57+
Prisma runs the database. `meta verify --codegen` and `--db` gate it. Setup, the mapping and
58+
what it refuses are in `typescript-prisma.md`. Any other ORM (TypeORM, Sequelize, MikroORM) is
59+
a generator you write: the Prisma one is a model to copy (`meta eject prisma-schema`).
60+
5561
**A SQL database that speaks another dialect's protocol.** Use that dialect: CockroachDB,
5662
Neon, Supabase, AlloyDB and Aurora PostgreSQL are `postgres`; Turso and libSQL are `sqlite`
5763
(or `d1` on Cloudflare); MariaDB and PlanetScale are `mysql`. Test the generated queries

‎agent-context/skills/metaobjects-codegen/references/dependencies-and-shared-models.md‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,14 @@ artifact is a contract whose bytes a cross-port corpus pins and whose hash
3838
consumers verify, so everything a consumer checks stays in the package, in the two
3939
functions the copy calls (`buildSharedModel`, `renderSharedModelFiles`). Do not
4040
replace those calls: an unmodified copy publishes the same bytes as the packaged
41-
generator. Only TypeScript can run it in Phase 1a. **Phase 1a is TypeScript and Python
42-
only, full stop** — TypeScript and Python are the only two ports that can
43-
*consume* a dependency at all today, and only the TypeScript toolchain can
44-
*publish* one; Java, Kotlin, and C# do not read `dependencies` yet (Phase 2).
41+
generator. To publish through a package, point its `target` inside the package
42+
(an npm package's directory listed in `files`; a Python package's directory shipped
43+
as package data), run `meta gen`, then release the package as usual; consumers
44+
declare an `npm` or `python` dependency on it. With no `version` option the
45+
manifest takes the nearest `package.json` version, else a `pyproject.toml`
46+
`[project]` version — pass `version` when neither is the package consumers install.
47+
Only TypeScript can run it in Phase 1a. TypeScript, Python, Java and
48+
Kotlin (through Java's loader and Maven plugin) can *consume* a dependency, and
49+
only the TypeScript toolchain can *publish* one; C# does not read
50+
`dependencies` yet (Phase 2).
4551
Full detail: `docs/features/metadata-dependencies.md`.

0 commit comments

Comments
 (0)