Skip to content

feat(postgresql): add support for table partitioning#7497

Merged
B4nan merged 57 commits intomikro-orm:nextfrom
liang799:feat/6944-postgresql-partition-support
Apr 19, 2026
Merged

feat(postgresql): add support for table partitioning#7497
B4nan merged 57 commits intomikro-orm:nextfrom
liang799:feat/6944-postgresql-partition-support

Conversation

@liang799
Copy link
Copy Markdown

@liang799 liang799 commented Apr 6, 2026

Summary

Adds PostgreSQL declarative partitioning via EntityOptions.partitionBy, extending existing entity options rather than introducing a new decorator (per discussion on #6944).

Closes #6944.

Changes

  • add partitionBy to EntityOptions and entity metadata
  • validate partition metadata during discovery (PK / unique-constraint coverage, inheritance / view / virtual guards)
  • support hash, list, and range partition definitions with array / comma-separated / raw SQL / callback expressions
  • generate partition by … parent DDL and explicit child partitions in PostgreSQL schema generation
  • introspect partitioned tables from pg_partitioned_table / pg_inherits to avoid perpetual diffs
  • surface partition changes through the schema comparator
  • emit partitionBy in entity-generator output for introspected tables
  • document the new API in schema-generator and defineEntity docs

Example

@Entity({
  partitionBy: {
    type: 'hash',
    expression: ['type'],
    partitions: 16,
  },
})
export class Event {

  @PrimaryKey()
  type!: string;

  @PrimaryKey()
  id!: number;

}

Notes

  • PostgreSQL-only. Other SQL platforms reject partitionBy at discovery with a platform-specific error.
  • Changing the partition definition of an existing table is not auto-migrated — write a manual migration for repartitioning.
  • Multi-level (sub-)partitioning is not modelled in declarative metadata and is intentionally invisible to schema diffing.

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 6, 2026

Codecov Report

❌ Patch coverage is 99.35760% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 99.65%. Comparing base (5c29304) to head (0876ba6).
⚠️ Report is 1 commits behind head on next.

Files with missing lines Patch % Lines
packages/sql/src/schema/partitioning.ts 98.61% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             next    #7497      +/-   ##
==========================================
- Coverage   99.65%   99.65%   -0.01%     
==========================================
  Files         265      267       +2     
  Lines       27621    28087     +466     
  Branches     7169     7775     +606     
==========================================
+ Hits        27526    27989     +463     
- Misses         89       92       +3     
  Partials        6        6              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Member

@B4nan B4nan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Apart from the broken CI checks, please also use lowercase for sql. Also ideally get to a complete code coverage.

@liang799 liang799 requested a review from B4nan April 7, 2026 04:41
@liang799 liang799 marked this pull request as draft April 7, 2026 19:25
@liang799
Copy link
Copy Markdown
Author

liang799 commented Apr 7, 2026

Old habits die hard, I keep subconsciously capitalizing SQL queries.
I will try to increase code coverage and fix formatting

@B4nan
Copy link
Copy Markdown
Member

B4nan commented Apr 7, 2026

I'll try to have a closer look later this week, for now, this is what claude things about the PR:

 Verified Findings

 1. HIGH — Perpetual getPreAlterTable error for non-trivial RANGE partitions

 Verified against a live Postgres 16 instance.

 pg_get_partkeydef and pg_get_expr canonicalize partition definitions in ways the PR's diffPartitioning cannot reverse:

 - A user-defined RANGE (((created_at AT TIME ZONE 'UTC')::date)) is stored by PG as RANGE ((((created_at AT TIME ZONE 'UTC'::text))::date)). The PR's normalization
 (/Users/adamek/htdocs/mikro-orm/mikro-orm/packages/sql/src/schema/partitioning.ts:124) only strips whitespace and " characters; it does not strip extra parentheses or ::text casts.
 - For timestamptz columns, a bound FROM ('2026-01-01') TO ('2026-02-01') is stored as FROM ('2026-01-01 00:00:00+00') TO ('2026-02-01 00:00:00+00').

 Once such a table exists, every schema:update produces a partition diff, which then hits getPreAlterTable (/Users/adamek/htdocs/mikro-orm/mikro-orm/packages/sql/src/dialects/postgresql/PostgreSqlSchemaHelper.ts:845)
  and throws Changing partition definitions for existing PostgreSQL tables is not supported automatically. The user is locked out of schema:update for the entire schema, not just the partitioned table.

 The integration test (/Users/adamek/htdocs/mikro-orm/mikro-orm/tests/features/schema-generator/SchemaGenerator.postgres.test.ts:131) only exercises the HASH case, where bounds are WITH (modulus, remainder) and the
 expression is a single bare column name — neither of which exercises the canonicalization paths above. Date columns and simple varchar LIST partitions roundtrip cleanly; timestamptz, complex expressions, and casts
 do not.

 2. MEDIUM — Missing validation that partition keys are part of every unique/primary key

 PostgreSQL requires the partition key to be a subset of every unique/primary key on a partitioned table, otherwise CREATE TABLE fails with unsupported PRIMARY KEY constraint with partition key definition (verified).
  The PR's validatePartitioning (/Users/adamek/htdocs/mikro-orm/mikro-orm/packages/core/src/metadata/MetadataValidator.ts:162) does not enforce this — users only learn about the violation when DDL execution fails. A
 clearer metadata-time error would be more helpful.

 3. LOW — validatePartitioning only rejects null/undefined expressions

 /Users/adamek/htdocs/mikro-orm/mikro-orm/packages/core/src/metadata/MetadataValidator.ts:167 uses expression == null. Empty string and empty array pass through and produce HASH () / RANGE () DDL that PG rejects.

 4. LOW — getPartitions query produces nspname = NULL and … when schema is undefined

 /Users/adamek/htdocs/mikro-orm/mikro-orm/packages/sql/src/dialects/postgresql/PostgreSqlSchemaHelper.ts:265 builds the WHERE clause with quoteValue(schema) even when schema is undefined. nspname = NULL is always
 false, so any tables in such a bucket are silently skipped. In practice getListTablesSQL always populates table_schema, so this currently never triggers, but the construction is fragile.

 5. LOW — splitPartitionName is lossy for multi-dot identifiers

 /Users/adamek/htdocs/mikro-orm/mikro-orm/packages/sql/src/schema/partitioning.ts:32 treats parts[0] as the schema and joins the remainder. A name like a.b.c parses as schema a, name b.c. Edge case.

 6. LOW — EntityPartitionType exported but unused

 /Users/adamek/htdocs/mikro-orm/mikro-orm/packages/core/src/metadata/types.ts:25 is never referenced anywhere in source. Either delete it or wire it into EntityPartitionBy['type'].

 7. LOW — partitioning.ts not exported from schema/index.ts barrel

 /Users/adamek/htdocs/mikro-orm/mikro-orm/packages/sql/src/schema/index.ts does not re-export the new partitioning.ts. The unit test imports it via a deep relative path. The functions seem intended to be
 internal-only, which is fine, but it's worth marking them @internal or moving them next to DatabaseTable to make the intent obvious.

 Severity Summary

 ┌─────┬──────────┬──────────────────────────────────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
 │  #  │ Severity │                 Area                 │                                                              Issue                                                               │
 ├─────┼──────────┼──────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
 │ 1   │ HIGH     │ Schema diff (postgres introspection) │ Perpetual diff / schema:update blocked for RANGE with timestamptz or complex expressions; only HASH/date-LIST round-trip cleanly │
 ├─────┼──────────┼──────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
 │ 2   │ MEDIUM   │ Metadata validation                  │ Partition key not validated against PK/unique columns                                                                            │
 ├─────┼──────────┼──────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
 │ 3   │ LOW      │ Metadata validation                  │ expression: '' / expression: [] not rejected                                                                                     │
 ├─────┼──────────┼──────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
 │ 4   │ LOW      │ Postgres introspection               │ Undefined-schema bucket produces nspname = NULL predicate                                                                        │
 ├─────┼──────────┼──────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
 │ 5   │ LOW      │ Helpers                              │ splitPartitionName lossy for a.b.c style names                                                                                   │
 ├─────┼──────────┼──────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
 │ 6   │ LOW      │ Public types                         │ EntityPartitionType exported but unused                                                                                          │
 ├─────┼──────────┼──────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
 │ 7   │ LOW      │ Module layout                        │ partitioning.ts not in schema/index.ts barrel                                                                                    │
 └─────┴──────────┴──────────────────────────────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

@liang799 liang799 marked this pull request as ready for review April 10, 2026 12:19
eyupcanakman and others added 2 commits April 18, 2026 16:02
…orm#7347)

## Summary
- Add `migration:log` and `migration:unlog` CLI commands
- `migration:log` marks a migration as executed without running it
- `migration:unlog` removes it from the executed list without reverting
- Add entries to the migrations documentation

Closes mikro-orm#5390

---------

Co-authored-by: Martin Adámek <banan23@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Summary

Adds a `discovery:export` CLI command that scans entity source files and
generates a TypeScript barrel file (mikro-orm#7323). The generated file provides:

- `export const entities = [...] as const` — for use in ORM config
- `export type Database = ...` — for typed `getKysely<Database>()` in DI
contexts (NestJS, etc.)

### Command usage

```bash
mikro-orm discovery:export [--path './src/entities/*.ts'] [--out ./entities.generated.ts] [--dump]
```

### Files changed

- **New:** `packages/cli/src/commands/DiscoveryExportCommand.ts` — the
command implementation
- **Modified:** `packages/cli/src/CLIConfigurator.ts` — register the
command
- **New:** `tests/features/cli/DiscoveryExportCommand.test.ts` — 14
tests
- **Modified:** `tests/features/cli/CLIHelper.test.ts` — updated command
list assertion
- **Modified:** `docs/docs/kysely.md` and
`docs/versioned_docs/version-7.0/kysely.md` — documentation

## Test plan

- [x] 14 unit tests covering: dump mode, file write, ESM/CJS imports,
EntitySchema dedup, decorator entities, multiple entities, driver
package resolution, config path fallback, error cases
- [x] `yarn build` passes (CLI package)
- [x] `yarn tsc-check-tests` passes
- [x] Full test suite passes (5314/5314)

Closes mikro-orm#7323

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…hatch (mikro-orm#7587)

## Summary

Three additive, non-breaking features for to-one relations, prompted by
[discussion
mikro-orm#7585](mikro-orm#7585).

### `LazyRef<T>`

Type-only marker for `@ManyToOne` / `@OneToOne`. Runtime is a plain
entity (no `Reference` wrapper, `instanceof User` returns `true`).
TypeScript restricts access to the primary key until `Loaded<>` narrows
it back to the full entity — no `.$` / `.get()` indirection needed on
loaded relations.

```ts
@manytoone(() => Author)
author!: LazyRef<Author>;

// or via defineEntity:
author: () => p.manyToOne(AuthorSchema).lazyRef()

book.author.id;                          // ok — PK always accessible
book.author.name;                        // compile error — not loaded
const loaded = await em.findOneOrFail(Book, 1, { populate: ['author'] });
loaded.author.name;                      // ok — Loaded<> strips the brand
```

Scope is to-one only. Collections keep `Collection<T>`.

### `Loadable` mixin

Adds `load()` / `loadOrFail()` to an entity's prototype —
Reference-style ergonomics for direct and LazyRef-typed relations. Ships
as `Loadable(Base)` plus pre-composed `LoadableBaseEntity`. `BaseEntity`
itself is deliberately untouched so `load` / `loadOrFail` aren't
reserved on existing subclasses.

```ts
class User extends LoadableBaseEntity { /* ... */ }
await user.load();          // Promise<User | null>
await user.loadOrFail();    // Promise<User>
```

### `unref()`

Typed escape hatch — inverse of the existing `ref()` helper. Narrows
`Ref<T>` | `LazyRef<T>` | `T` down to `T` for cases where you know the
relation is populated but can't thread `Loaded<>` through a function
signature.

```ts
import { unref } from '@mikro-orm/core';

function logAuthor(book: Book) {
  // `book.author` is typed as `LazyRef<Author>` — `.name` would be a compile error
  console.log(unref(book.author).name);
}
```

Works for `Ref<T>` (calls `.unwrap()`), `LazyRef<T>` (identity cast),
plain `T` (passthrough), and `null` / `undefined` (passthrough).

### Non-breaking

- `BaseEntity`, `Ref<T>`, plain relations, and `@ManyToOne({ ref: true
})` all unchanged.
- `LazyRef<T>` is opt-in per property.
- `.lazyRef()` is opt-in per builder chain and leaves runtime metadata
untouched.

### Type performance

`LazyRef` integration is isolated to `AutoPath` / `Loaded<>` narrowing
via a new `ExtractTypeWithLazyRef` helper — the existing `ExtractType`
hot path (`EntityData`, `RequiredEntityData`, `IsOptional`) pays no
cost. New benches in `tests/bench/types/lazy-ref.ts` compare
like-for-like against `Ref<T>`; LazyRef is slightly cheaper for loaded
narrowing (no `LoadedReference` intersection). All existing benchmark
baselines have been refreshed and the full `yarn bench:types` run shows
0% delta.
@B4nan B4nan changed the base branch from master to next April 19, 2026 08:02
@B4nan B4nan changed the title feat(postgresql): add partitioned table support via EntityOptions.partitionBy feat(postgresql): add support for table partitioning Apr 19, 2026
B4nan and others added 6 commits April 19, 2026 11:18
…ator gaps

- preserve double quotes and internal whitespace inside single-quoted SQL
  literals in partitioning normalizers (quote-aware mapping helper)
- align partition expression parsing with MetadataValidator for
  comma-separated identifier strings
- thread platform.quoteIdentifier through getTablePartitioning so
  generated DDL emits properly-quoted partition key columns
- split schema-qualified partition names on the first dot (schema.name)
  instead of keeping multi-dot names whole
- emit comments/indexes/checks/triggers before partition children in
  createTable for more readable generated scripts
- emit partitionBy entity option from entity-generator source files
- drop partitioning docs from the frozen v7.0 snapshot (docs live under
  docs/docs only)
- exercise remaining branches in partitioning helpers: callback-expression
  passthrough, raw-SQL fallback, physical column-name lookup, empty-key
  guard, `from` bound without `to`, and empty bound string
- cover MetadataValidator partition paths: callback/comma-separated/raw
  expressions, unique-property & unique-constraint coverage errors,
  no-op paths for unresolved keys and property-less uniques
- short-circuit path in PostgreSqlSchemaHelper.getPartitions when all
  schema buckets are empty
Adds entity-generator and partitioning-helper coverage for callback
`expression` values so the quoter-aware branches are reached both with
and without a custom quoter.
Co-authored-by: Martin Adámek <banan23@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Schema Generator is the right home for partition documentation; the
defineEntity page is for explaining the helper, not for platform-specific
table features.
- `Platform.validateMetadata` now rejects `partitionBy` on platforms that
  don't support partitioned tables, so the error surfaces at ORM init
  (discovery) rather than only at schema-update time; MongoDB/MSSQL
  overrides delegate to super. The duplicate check in
  `DatabaseSchema.fromMetadata` is removed.
- `MetadataValidator.getPartitionKeyFields` now resolves each key
  independently: resolvable keys still drive PK/unique-coverage checks
  even when other tokens in a comma-separated expression can't be
  mapped to a property or column.
B4nan and others added 13 commits April 19, 2026 14:47
- preserve `TO` tokens inside quoted literals when normalizing
  `from ... to ...` range bounds
- parse compact `HASH(expr)` definitions without dropping the expression
- return empty string for empty partition bounds instead of malformed
  `for values`
- resolve partition keys via `meta.root.properties` to match
  `MetadataValidator`
- drop the unreachable callback branch from the entity generator
  `partitionBy` declaration (only string/array expressions reach the
  generator via `toEntityPartitionBy`)
…partition-support

# Conflicts:
#	packages/core/src/metadata/types.ts
#	packages/sql/src/dialects/postgresql/PostgreSqlSchemaHelper.ts
#	packages/sql/src/schema/DatabaseTable.ts
#	packages/sql/src/typings.ts
- only fold midnight timestamps with no offset or UTC offset in partition
  diffing (non-UTC offsets are semantically distinct)
- emit function-typed partition expressions verbatim in entity generator
  instead of stringifying the source as a quoted string literal
- include from/to definitions in the unsupported-repartition error so
  normalization mismatches are easier to diagnose
- attribute partition validation errors to the root entity (where the
  unique constraint lives) rather than the validated meta
…og introspection

Addresses staff-review findings on the partitioning work:

- splice `partition by …` into `create table` via slice instead of `.replace(/;$/, …)`
  so dollar-quoted literals, `$&`, and `$1..$9` in user expressions are not interpreted
  as regex back-references
- throw on unresolved partition keys during validation (and in the DDL path) so DDL
  cannot silently emit references to unknown columns
- require an explicit offset on `YYYY-MM-DD 00:00:00` literal stripping to avoid
  false-negative diffs when a text/varchar list partition value legitimately looks
  like a midnight timestamp
- quote-aware split of `type ` prefix in `toEntityPartitionBy` so bounds containing
  spaces inside quoted literals round-trip correctly
- filter child partitions in `getListTablesSQL` via a (schema, relname) anti-join so
  children living in non-`search_path` schemas are not surfaced as untracked tables
- collapse the per-schema OR tree in `getPartitions` into a single `values(…)` join
  keyed by (schema, table) so the query stays compact and sargable
- mark `setPartitioning` `@internal` to match peer `DatabaseTable` mutators
- fail loud in the entity generator if a callback-form `partitionBy.expression` ever
  reaches source emission, since `fn.toString()` would produce uncompilable TypeScript
- propagate the `Entity` generic to `EntityMetadata.partitionBy` so internal code
  retains narrowed column types in callback expressions
- document the opaque-expression coverage-skip in `getPartitionKeyFields` and simplify
  `normalizePartitionBound` to a single keyword-lowering pass that stays inside
  `mapOutsideLiterals`
- add a `defineEntity` section to the docs so the schema-generator reference has a
  matching partition example on the other side
…ation

- extend `partitionBy.partitions` for `hash` to accept a name array alongside the
  numeric count (names may carry a `schema.name` or quoted `"schema"."name"` prefix)
- have `splitPartitionName` honour double-quoted identifiers so partition names
  containing `.` (e.g. `"my.schema"."part"`) are parsed correctly
- also strip the `00:00:00` time component when followed by an explicit
  `::timestamp[tz]` cast, so `timestamp without time zone` range partitions diff
  cleanly on round-trips (catalog output carries no offset for non-tz)
- declare the legacy `inheritance?: 'tpt'` field on `EntityMetadata` so the
  validator's inheritance check no longer needs an inline cast
- preserve round-tripped hash partition names when the catalog names deviate from
  the default `${tableName}_N` pattern, and drop the redundant `public.` prefix
  when the child's schema matches the parent's
- document the symmetric `::text` strip behaviour in `normalizePartitionLiterals`
- drop the PG-only partitioning callout from `defineEntity` docs (one canonical
  entry in `schema-generator.md` is enough)
…ator output

- entity-generator now quotes custom hash partition names so introspected
  `partitions: ['a', 'b']` arrays round-trip as valid TypeScript.
- `getPartitions` resolves undefined schema buckets against `current_schema()`
  instead of wildcarding across every schema that shares the table name.
- `splitCommaSeparatedIdentifiers` (new shared util) respects double-quoted
  identifiers containing commas; replaces the previous regex + naive split.
- `MetadataValidator.hasPartitionExpression` guards against non-string array
  entries so bad input surfaces as a clean `MetadataError`.
- `skipQuotedLiteral` now returns past the end for unterminated literals so
  callers don't silently drop the tail character.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ate partition names

PostgreSQL's pg_get_expr emits MINVALUE, MAXVALUE, and NULL in uppercase,
but user-supplied lowercase bounds were not normalized, producing a
permanent false-positive diff that could not be resolved (changing
partitioning is blocked by getPreAlterTable). Add them to the bound
keyword regex so case-folding happens symmetrically on both sides.

Validate duplicate partition names for both hash (array form) and
list/range partitions so users get a clear MetadataError at discovery
time instead of a late, opaque PG DDL failure.

Distinguish the composite-column case from the unknown-key case in
resolvePartitionKey / resolvePartitionKeyField, naming the physical
columns so the remedy is actionable.

Also drop a redundant normalizePartitionLiterals call in
normalizePartitionBound; normalizePartitionSqlFragment already runs it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Partition name collisions that only surface after PostgreSQL's identifier
folding (e.g. `Part_1` vs `part_1`) or between an explicit name and another
partition's auto-generated `${tableName}_${index}` default previously slipped
past the validator and only failed at DDL execution. Normalize names the way
PG resolves them — case-fold unquoted segments, preserve quoted ones — and
include the defaulted names in the list/range duplicate check.

Also document the raw-SQL branch of `resolvePartitionExpression` (identifiers
inside opaque expressions are emitted verbatim) and add an integration test
that exercises partitioning alongside indexes, check constraints, and
triggers.
…ts filter

The `pg_inherits` anti-join in `getListTablesSQL` was rewritten to compare on
(schema, table) pairs so cross-schema partitions get filtered correctly even
when their schema isn't on the session `search_path`. The Migrator test's
expected query string was still on the old `table_name not in (...)` form.
…verage

Closes the remaining coverage gaps on the new partition helpers — quoted
identifiers with embedded "" escape sequences, and the empty/malformed
definition fallbacks in normalizePartitionDefinition and toEntityPartitionBy.
…branches

Pins coverage on the last four branches codecov flagged: hash partition
names with more than one dot, partition keys that resolve to multi-column
properties, MetadataDiscovery surfacing the unsupported-platform error
through MikroORM.init, and the entity generator's refusal to emit
callback-form partitionBy.expression.
The `connect: false` flag is honored at runtime but isn't part of the
driver's Options type; cast through the driver's Options to keep the
typecheck green (mirrors advanced-index-features.postgres.test.ts).
…partition-support

# Conflicts:
#	packages/sql/src/schema/DatabaseTable.ts
@B4nan B4nan merged commit 48bfdb2 into mikro-orm:next Apr 19, 2026
19 of 20 checks passed
B4nan added a commit that referenced this pull request Apr 20, 2026
## Summary

Adds PostgreSQL declarative partitioning via
`EntityOptions.partitionBy`, extending existing entity options rather
than introducing a new decorator (per discussion on #6944).

Closes #6944.

## Changes

- add `partitionBy` to `EntityOptions` and entity metadata
- validate partition metadata during discovery (PK / unique-constraint
coverage, inheritance / view / virtual guards)
- support `hash`, `list`, and `range` partition definitions with array /
comma-separated / raw SQL / callback expressions
- generate `partition by …` parent DDL and explicit child partitions in
PostgreSQL schema generation
- introspect partitioned tables from `pg_partitioned_table` /
`pg_inherits` to avoid perpetual diffs
- surface partition changes through the schema comparator
- emit `partitionBy` in entity-generator output for introspected tables
- document the new API in `schema-generator` and `defineEntity` docs

## Example

```ts
@entity({
  partitionBy: {
    type: 'hash',
    expression: ['type'],
    partitions: 16,
  },
})
export class Event {

  @PrimaryKey()
  type!: string;

  @PrimaryKey()
  id!: number;

}
```

## Notes

- PostgreSQL-only. Other SQL platforms reject `partitionBy` at discovery
with a platform-specific error.
- Changing the partition definition of an existing table is not
auto-migrated — write a manual migration for repartitioning.
- Multi-level (sub-)partitioning is not modelled in declarative metadata
and is intentionally invisible to schema diffing.

---------

Co-authored-by: Eyüp Can Akman <eyupcanakman@gmail.com>
Co-authored-by: Martin Adámek <banan23@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Vasil Rangelov <boen.robot@gmail.com>
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.

PostgreSQL PARTITION BY support

4 participants