question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Introspection can't get composite primary key for partitioned table

See original GitHub issue

Bug description

Hello 👋🏻 I’m trying to add Prisma to existing project and it fails on introspection step. We have partitioned table with composite keys and prisma can’t understand what primary key is in the original table. The fun fact is that it successfully introspected the same primary key for partitions themselves.

*** WARNING ***

The following models were commented out as they do not have a valid unique identifier or id. This is currently not supported by the Prisma Client.
- "blocks"
- "comments"
- "reactions"

Blocks, comments and reactions are tables with partitions

How to reproduce

  1. Create a partitioned table with composite id. For example here is sql to create our blocks table:
-- Table: public.blocks

CREATE TABLE IF NOT EXISTS public.blocks
(
    id uuid NOT NULL,
    account text COLLATE pg_catalog."default" NOT NULL,
    holder_type_id uuid NOT NULL,
    holder_entity_id uuid NOT NULL,
    block_source_id uuid,
    type block_type NOT NULL,
    kind block_kind NOT NULL,
    created_by uuid NOT NULL,
    created_at timestamp without time zone NOT NULL DEFAULT now(),
    modified_at timestamp without time zone NOT NULL DEFAULT now(),
    rank integer NOT NULL,
    link_comment text COLLATE pg_catalog."default",
    content jsonb NOT NULL,
    is_deleted boolean NOT NULL DEFAULT false,
    CONSTRAINT blocks_pkey PRIMARY KEY (account, id),
    CONSTRAINT block_source_block_fk FOREIGN KEY (block_source_id, account)
        REFERENCES public.blocks (id, account) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE CASCADE,
    CONSTRAINT blocks_account_block_source_id_fkey FOREIGN KEY (block_source_id, account)
        REFERENCES public.blocks_p2_0 (id, account) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE CASCADE,
    CONSTRAINT blocks_account_block_source_id_fkey1 FOREIGN KEY (block_source_id, account)
        REFERENCES public.blocks_p2_1 (id, account) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE CASCADE,
) PARTITION BY HASH (account);

ALTER TABLE IF EXISTS public.blocks
    OWNER to postgres;

-- Index: entity_blocks_idx

CREATE INDEX IF NOT EXISTS entity_blocks_idx
    ON public.blocks USING btree
    (account COLLATE pg_catalog."default" ASC NULLS LAST, holder_type_id ASC NULLS LAST, holder_entity_id ASC NULLS LAST)
;

-- Partitions SQL

CREATE TABLE public.blocks_p2_0 PARTITION OF public.blocks
    FOR VALUES WITH (modulus 2, remainder 0);

ALTER TABLE IF EXISTS public.blocks_p2_0
    OWNER to postgres;
CREATE TABLE public.blocks_p2_1 PARTITION OF public.blocks
    FOR VALUES WITH (modulus 2, remainder 1);

ALTER TABLE IF EXISTS public.blocks_p2_1
    OWNER to postgres;
  1. run npx prisma db pull

Expected behavior

Primary key should be introspected correctly for partitioned table. Now it prevents me from using Prisma completely since I can’t generate a client

Prisma information

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

/// The underlying table does not contain a valid unique identifier and can therefore currently not be handled by the Prisma Client.
model blocks {
  id                                                      String           @db.Uuid
  account                                                 String
  holder_type_id                                          String           @db.Uuid
  holder_entity_id                                        String           @db.Uuid
  block_source_id                                         String?          @db.Uuid
  type                                                    block_type
  kind                                                    block_kind
  created_by                                              String           @db.Uuid
  created_at                                              DateTime         @default(now()) @db.Timestamp(6)
  modified_at                                             DateTime         @default(now()) @db.Timestamp(6)
  rank                                                    Int
  link_comment                                            String?
  content                                                 Json
  is_deleted                                              Boolean          @default(false)
  blocks                                                  blocks?          @relation("blocksToblocks_account_block_source_id", fields: [account, block_source_id], references: [account, id], onDelete: Cascade, onUpdate: NoAction, map: "block_source_block_fk")
  blocks_p2_0_blocks_account_block_source_idToblocks_p2_0 blocks_p2_0?     @relation("blocks_account_block_source_idToblocks_p2_0", fields: [account, block_source_id], references: [account, id], onDelete: Cascade, onUpdate: NoAction)
  blocks_p2_1_blocks_account_block_source_idToblocks_p2_1 blocks_p2_1?     @relation("blocks_account_block_source_idToblocks_p2_1", fields: [account, block_source_id], references: [account, id], onDelete: Cascade, onUpdate: NoAction, map: "blocks_account_block_source_id_fkey1")
  other_blocks                                            blocks[]         @relation("blocksToblocks_account_block_source_id")
  blocks_p2_0_blocksToblocks_p2_0_account_block_source_id blocks_p2_0[]    @relation("blocksToblocks_p2_0_account_block_source_id")
  blocks_p2_1_blocksToblocks_p2_1_account_block_source_id blocks_p2_1[]    @relation("blocksToblocks_p2_1_account_block_source_id")

  @@ignore
}

model blocks_p2_0 {
  id                                                 String      @db.Uuid
  account                                            String
  holder_type_id                                     String      @db.Uuid
  holder_entity_id                                   String      @db.Uuid
  block_source_id                                    String?     @db.Uuid
  type                                               block_type
  kind                                               block_kind
  created_by                                         String      @db.Uuid
  created_at                                         DateTime    @default(now()) @db.Timestamp(6)
  modified_at                                        DateTime    @default(now()) @db.Timestamp(6)
  rank                                               Int
  link_comment                                       String?
  content                                            Json
  is_deleted                                         Boolean     @default(false)
  blocks_blocksToblocks_p2_0_account_block_source_id blocks?     @relation("blocksToblocks_p2_0_account_block_source_id", fields: [account, block_source_id], references: [account, id], onDelete: Cascade, onUpdate: NoAction, map: "block_source_block_fk") @ignore
  blocks_blocks_account_block_source_idToblocks_p2_0 blocks[]    @relation("blocks_account_block_source_idToblocks_p2_0") @ignore

  @@id([account, id])
  @@index([account, holder_type_id, holder_entity_id])
}

model blocks_p2_1 {
  id                                                 String      @db.Uuid
  account                                            String
  holder_type_id                                     String      @db.Uuid
  holder_entity_id                                   String      @db.Uuid
  block_source_id                                    String?     @db.Uuid
  type                                               block_type
  kind                                               block_kind
  created_by                                         String      @db.Uuid
  created_at                                         DateTime    @default(now()) @db.Timestamp(6)
  modified_at                                        DateTime    @default(now()) @db.Timestamp(6)
  rank                                               Int
  link_comment                                       String?
  content                                            Json
  is_deleted                                         Boolean     @default(false)
  blocks_blocksToblocks_p2_1_account_block_source_id blocks?     @relation("blocksToblocks_p2_1_account_block_source_id", fields: [account, block_source_id], references: [account, id], onDelete: Cascade, onUpdate: NoAction, map: "block_source_block_fk") @ignore
  blocks_blocks_account_block_source_idToblocks_p2_1 blocks[]    @relation("blocks_account_block_source_idToblocks_p2_1") @ignore
  comments                                           comments[]  @ignore
  reactions                                          reactions[] @ignore

  @@id([account, id])
  @@index([account, holder_type_id, holder_entity_id])
}

enum block_kind {
  field
  native
  link
  transclusion
}

enum block_type {
  file
  view
  rich_text @map("rich-text")
}

Environment & setup

  • OS: MacOs Monterey 12.0.1
  • Database: PostgreSQL 13.3 (Debian 13.3-1.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit
  • Node.js version: v16.13.1

Prisma Version

prisma                  : 3.7.0
@prisma/client          : Not found
Current platform        : darwin
Query Engine (Node-API) : libquery-engine 8746e055198f517658c08a0c426c7eec87f5a85f (at node_modules/@prisma/engines/libquery_engine-darwin.dylib.node)
Migration Engine        : migration-engine-cli 8746e055198f517658c08a0c426c7eec87f5a85f (at node_modules/@prisma/engines/migration-engine-darwin)
Introspection Engine    : introspection-core 8746e055198f517658c08a0c426c7eec87f5a85f (at node_modules/@prisma/engines/introspection-engine-darwin)
Format Binary           : prisma-fmt 8746e055198f517658c08a0c426c7eec87f5a85f (at node_modules/@prisma/engines/prisma-fmt-darwin)
Default Engines Hash    : 8746e055198f517658c08a0c426c7eec87f5a85f
Studio                  : 0.445.0

Issue Analytics

  • State:open
  • Created 2 years ago
  • Comments:10 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
jineshshah36commented, Aug 5, 2022

We have adopted prisma in a very large postgres database that syncs integration data and want to partition some tables. I’d be very excited to have a way (even if suboptimal) to achieve partitioning. We already write many manual migrations that cannot be expressed in prisma as it is. I don’t mind doing that for partitions, but the composite key issue is a blocker.

2reactions
MrLohcommented, May 31, 2022

if someone could point me to where the inference of the partitioned table needs to be fixed, I can have a look, but this codebase is very large and I would need some guidance to tackle this, but I can give it a shot

Read more comments on GitHub >

github_iconTop Results From Across the Web

Primary Key Index not getting picked on Partitioned Table
This table is range partitioned on account_id. There is composite primary key (account_id, b_key) on this table.
Read more >
Composite Primary Key on partitioned tables, and Foreign Keys
Create a table with a PRIMARY KEY that references the partition scheme. ... I cannot decide whether to use composite FKs, referencing both ......
Read more >
Composite primary key declaration through Convention for ...
I need to use Fluent-nHibernate against a table with a composite primary key (Azure Table, primary keys being ...
Read more >
Partition Data to Enable Joins - ksqlDB Documentation
Tables are always partitioned by their PRIMARY KEY , and ksqlDB doesn't allow repartitioning of tables, meaning you can only use a table's...
Read more >
Schema design best practices | Cloud Spanner
The following table definition that uses a timestamp-based primary key as the ... The hotspot is created because a single Spanner server will...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found