Skip to content

codegen-ts: projection field extends drops isArray / storage:jsonb — array/jsonb columns generate as string, diverging from the Kotlin port #204

Description

@dmealing

Summary

When a projection (view) field is bound to a base-entity field via a dotted extends, the @metaobjectsdev/codegen-ts port does not carry the base field's isArray / storage: jsonb through the extends resolution — but the Kotlin port does. So for identical metadata, the two ports emit different types for the same projection field, and the TS output is both wrong and internally inconsistent.

Repro (minimal)

Base entity with an array column and a jsonb column:

object.pojo:
  name: SomeEntity
  children:
    - field.string: { name: conditions, isArray: true }                    # → text[]
    - field.object: { name: profile, objectRef: Profile, storage: jsonb }  # → jsonb

A projection binds them via bare extends (no restated shape — this is intentional: keeping the projection a pure extends passthrough is what keeps it meta migrate-ready):

object.projection:
  name: SomeEntityView
  children:
    - field.string: { name: conditions, extends: "…::SomeEntity.conditions" }
    - field.object: { name: profile,    extends: "…::SomeEntity.profile" }

Kotlin codegen — correct (resolves extends and carries the shape):

val conditions: List<String>
val profile: JsonElement

TS codegen (codegen-ts 0.15.21) — wrong: both the Drizzle column and the Zod schema flatten the array to a scalar string, and they even disagree with each other on the jsonb column:

// drizzle table
conditions: text("conditions"),   // should be text("conditions").array()
profile:    jsonb("profile"),      // drizzle gets jsonb right…
// zod schema
conditions: z.string(),            // should be z.array(z.string())
profile:    z.string(),            // …but zod says string — internally inconsistent with the drizzle jsonb() above

Impact

The projection's generated TS type is a type-lie: a text[] column is typed string, and a jsonb column is typed string even though the same generated file's Drizzle side declares jsonb(). Any consumer that trusts the generated type — or .parse()s a real row through the generated Zod schema — gets the wrong type or a runtime validation failure, because the actual wire shape (defined by the Kotlin-generated projection that backs the REST/read API) is an array / object.

This is a lagging-port divergence: the Kotlin port carries isArray / storage through extends, the TS port drops it. The ports should agree on the resolved field shape (cf. "keep all ports in sync").

Suggested fix

In codegen-ts, when resolving a projection field's extends, inherit the referenced base field's isArray and storage / dbColumnType (jsonb) the same way the Kotlin port does — so the Drizzle column, the Zod schema, and the Kotlin type all agree. Fixing it in the generator (rather than forcing adopters to re-state isArray/storage on every projection field) also preserves the pure-extends passthrough shape that keeps projections meta migrate-ready.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions