Skip to content

MetaObjects 1.0.13

Choose a tag to compare

@dmealing dmealing released this 03 Oct 07:28
· 106 commits to main since this release

npm 1.0.13 (all 14 @metaobjectsdev/* packages in lockstep), PyPI 1.0.13, NuGet 1.0.13 and
Maven Central 8.0.13. metamodelVersion stays 1.0. Gated by a private 1.0.13-rc.1 build of the
release commit on the adopter estate (rc-gate.sh 7/7) and a full local CI run (--strict-toolchains)
on that commit. Read "Upgrade impact" below if any entity name is already plural — its REST path
and generated names change.

Fixed

  • Cross-port: an already-plural entity name no longer doubles in generated API/code-surface
    names.
    ProgramPurchaseStats used to come out ProgramPurchaseStatses in the REST
    collection path, generated hook/query/finder/list function names, and DbSet/collection
    names — a real adopter shipped six such URLs. Every port's pluralizer now treats a word
    ending in "s" as already-plural UNLESS the character before that final "s" is one of
    s/u/i/a (so Stats/Settings/Series/News/Analytics/Photos stay unchanged, while
    Status/Address/Bonus/Alias/Gas/Analysis keep pluralizing exactly as before —
    the heuristic's one documented miss is Lens → Lens, correct plural Lenses).

    Upgrade impact — read before regenerating. If any entity name in your model is
    already a plural noun (Stats, Settings, Series, and the like):

    • The REST collection path changes. /program_purchase_statses becomes
      /program_purchase_stats. A client still calling the old doubled URL gets a plain
      404, not a redirect — update callers before or alongside the regen.
    • Generated hook, query, finder, and list function/method names change too
      (useProgramPurchaseStatses → useProgramPurchaseStats, listProgramPurchaseStatses
      → listProgramPurchaseStats, the C# DbSet property, the Java/Python finder/router
      names). Any hand-written code importing or calling the OLD doubled symbol fails to
      compile (TS/C#/Kotlin) or import (Python) after you regenerate — grep for the old
      spelling across your own code, not just generated output.
    • There is no per-entity override for a route or generated hook/finder/list name.
      TypeScript's variableNameFromEntity/CollectionNameOptions.overrides renames only
      the Drizzle collection VARIABLE — it does not touch the REST path or any hook/query/
      finder/list name. If the new spelling is wrong for your API, the fix is to rename the
      entity itself; there is no config knob that renames only the generated surface.
    • Default PHYSICAL table and column names do NOT change. The fallback used when
      metadata declares no explicit physical name is explicitly frozen at the old
      suffix-only rule in every port (a new, separately-named, byte-for-byte-preserved
      function where the two pluralizers were previously the same one) — meta migrate
      proposes no rename for an already-plural entity you didn't touch.
    • Two entities in one generation run whose names now land on the same API-surface
      collection name is a GENERATION ERROR, not a silent collision.
      Address + Addresses
      (or Order + Orders) both resolve to /addresses / /orders once an already-plural
      name stops doubling — before this fix they did not collide (Addresses doubled to
      addresseses). Every port now refuses such a model outright, before any generator
      runs, naming both entities and the colliding name; rename one entity to proceed. New
      cross-port fixture corpus fixtures/naming-conformance/ carries both the already-plural
      cases and the expected-collision cases, run by every port.

    Fixing the doubling also surfaced two further, narrower defects it was incidentally
    masking: a TypeScript already-plural entity's generated Drizzle collection variable name
    could collide with its own singular row variable in the same statement (const [x] = await db.insert(x)..., a TDZ compile error) — the colliding local variable now gets a
    Row suffix only in that exact case; and a C# already-plural entity's own DbSet
    property name could collide with its own entity TYPE name inside OnModelCreating (C#
    resolves a bare same-named reference to the DbSet member before the type, the same
    shadowing class as the pre-existing Address/Addresses cross-entity hazard) — the
    TPH-discriminator and int-backed-enum nested-type references are now global::-qualified
    when, and only when, the owning entity's name is itself already-plural.

  • Kotlin: two pre-existing generated-controller compile defects, found extending the
    exposedApi=1 controller-tier compile check.
    Both were excluded (not fixed) when that
    check landed; both are fixed now, for exposedApi=0 and exposedApi=1 alike, with no
    exclusions left. (1) A filterable field.inet column's generated filter dispatch emitted
    ordering operators (gt/gte/lt/lte) that java.net.InetAddress cannot satisfy (it is
    not Comparable) — the per-field operator gate now derives from the same
    com.metaobjects.query.FilterOps single source of truth the generated <Entity>FilterAllowlist
    already reads, so the controller can no longer emit an operator the allowlist itself would
    refuse to admit. (2) The field.string @dbColumnType=uuid physical escape hatch bound a
    native Column<UUID> on the generated Exposed table while the generated entity/controller
    assumed String (per ADR-0037, the escape hatch is physical-only) — a mismatch on every
    filter comparison and the PATCH bind. The table now binds a Column<String> instead (a new
    package-shared uuidString(...) extension that persists through the native Postgres uuid
    type while converting only at the Kotlin-value boundary), agreeing with the entity/controller
    and with how every other port treats the same escape hatch. A new exposedApi=0 controller-
    tier compile test (integration-tests-kotlin) closes the matching gap on the default/stable
    output path, which nothing had compiled over the full shared fitness corpus before.