Skip to content

feat: type overrides, Postgres enum shared types, and unmapped-type crash fix (#93) - #94

Merged
spinlud merged 12 commits into
masterfrom
type-overrides
Oct 7, 2026
Merged

spinlud merged 12 commits into
masterfrom
type-overrides

Conversation

@spinlud

@spinlud spinlud commented Oct 7, 2026

Copy link
Copy Markdown
Owner

Implements #93 (13.2.0): unmapped types no longer crash, Postgres user-defined types are detected, and users can declare type overrides. Includes review fixes and a dependency refresh. All codegen uses the TypeScript compiler API.

Closes #93.

Unmapped types (a169ef9)

  • mapDbTypeToJs now returns string | undefined in the dialect contract and in all five dialects.
  • Native format types an unmapped column unknown instead of crashing in createTypeNodeFromName. Decorators keep any until the next major.
  • The fetch-time warning in each dialect is replaced by a shared warnUnmappedTypes pass in ModelBuilder.build(). It names schema.table.column, says which type the column received, and points to --type-overrides-file. Columns covered by an override get no warning.

Type overrides (7c69e89, 5e2074d, 7386af7)

  • Overrides come from --type-overrides-file / -y, or from IConfig.metadata.typeOverridesFile / metadata.typeOverrides. Setting both is a validation error.
  • The file has two optional sections:
    • types: <type> or <schema>.<type>
    • columns: <table>.<column> or <schema>.<table>.<column>
  • Each entry sets tsType, dataType, or both.
  • tsType is parsed with the compiler API into a type node. Unions, object types and import('pkg').Type all work, and no imports are generated.
  • dataType is parsed into the structured {key, args} form. Only identifiers, calls and string or number literals are accepted, with an optional DataTypes. prefix. Each key must be a real column data type, so dialect namespaces and ABSTRACT are rejected. Raw user text is never emitted as code.
  • Precedence, resolved for tsType and dataType independently:
    • a column key beats a type key;
    • a schema-qualified key beats an unqualified one;
    • any override beats what the generator derives;
    • a side left unset keeps the generator's result.
  • Keys match case-insensitively.
  • Every validation error is reported as [ValidationError] and names the entry. Entries that matched no column produce one combined warning.
  • ITypeOverride, ITypeOverrides and IColumnTypeOverride are exported.
  • The Json shared type is emitted only while some column still uses it.

Postgres user-defined types (219dd7e, 46d0e00)

  • Enum labels are read from pg_type, pg_enum and pg_namespace, with one cached query per schema. Lookup uses the column's UDT schema and name, so enum arrays and enums from other schemas resolve.
  • Each enum becomes a shared type, e.g. PlanTier = 'free' | 'pro', in a generated enums.ts. Both formats import it type-only.
  • Enum columns emit DataTypes.ENUM(...) with labels in database order. Enum arrays emit an ARRAY of ENUM and are typed PlanTier[].
  • enums.ts is generated only when a column still uses an enum after overrides.
  • Name clashes get deterministic renames, each with a warning:
    • an enum from a schema none of the generated tables belong to gets a schema prefix;
    • a clash with a model name or with any identifier a model file declares or imports gets an Enum suffix;
    • remaining ties get a numeric suffix.
  • citext maps to string / CITEXT. Domains already resolve to their underlying type; a test now covers this.
  • Enum labels containing ', \, " or a newline now render as valid TypeScript string literals in decorators data types. This also fixes MySQL/MariaDB enums with such labels.

Docs (5e8a2d0, c0e4fd7)

  • README gains "Type overrides" and "Postgres user-defined types" sections. They cover the file format, precedence, the type key for each dialect, validation, enum naming, and the caveats about sync() and enum OIDs.
  • The README copy of --help now matches the real output.
  • CONTEXT.md gains a "Types" glossary section.

Dependencies (44bf442, d91f65a, 55b1557)

  • npm update brought packages to their newest versions within the existing ranges.
  • npm audit fix, without --force, raised moment and brace-expansion. Runtime advisories went from 4 (1 high) to 2 moderate.
  • npm 11 converted the lockfile to format v3.
  • yargs 18 needed no code changes; @types/yargs stays at 17.
  • tedious 20 (dev only) requires Node >= 22, which CI meets.
  • Remaining advisories, both accepted:
    • uuid via sequelize; npm's only suggested fix is a downgrade to sequelize 3;
    • dev-only js-yaml / sprintf-js advisories via jest and tedious; their only suggested fixes are downgrades too.
  • Not bumped on purpose: TypeScript 7, change-case 5, and the @types/node major.

Tests

  • Through ModelBuilder.build() with a stub dialect (typeOverrides.test.ts, sharedEnumTypes.test.ts, modelBuilder.test.ts):

    • every precedence rule and validation error;
    • name clashes;
    • removal of an unused enum shared type;
    • a strict compile of the generated output.
  • CLI config tests check that -y reaches the config.

  • Integration:

    • a typeOverrides scenario runs in all five dialects;
    • a Postgres userDefinedTypes scenario covers an enum, an enum array, a cross-schema enum, a domain, citext, and an enum shared by two tables, and round-trips their values.
  • Results, run locally:

    Suite Passed
    Unit 420
    SQLite (golden unchanged) 90
    Postgres 170
    MySQL 166
    MariaDB 164
    mssql (on Node 22) 148

    MariaDB was not rerun after the final dependency commits.

@spinlud
spinlud merged commit 90c9b7c into master Oct 7, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unmapped types: native crash fix, Postgres user-defined type detection, and type overrides

1 participant