Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

Policy expressions do not map `@map`-ed enum values in several comparison shapes

Đang mở
#2,867 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
5/5
Thời gian dự kiến
Hơn một tuần
Mức phù hợp với người mới
35/100
Loại issue
Lỗi
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
postgresql, sqlite, typescript
Lĩnh vực
authorization

Hướng nghiên cứu

Read the enum name mapper and policy transformer, then compare their handling of the listed policy expressions with the generated TypeScript schema’s enum representation. Reproduce the failing comparison and array cases on SQLite and PostgreSQL; done means mapped enum values work for those cases without breaking the listed passing cases.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

plugin runtime

Summary

When an enum has @map-ed member values, the ORM's name mapper translates enum names to database values at SQL execution time by pattern-matching Kysely nodes (column = value, column IN (...), insert/update values, select projections). Several SQL shapes produced by the policy plugin never reach the mapper in a form it recognizes, so policies silently return no rows on SQLite or fail with type errors on PostgreSQL.

Follow-up to #2807, which fixed field in [A, B] and field in Enum for this case.

Schema used for all cases

enum PostStatus {
    DRAFT     @map('draft')
    ACTIVE    @map('active')
    CANCELLED @map('cancelled')
}

model User {
    id     Int        @id @default(autoincrement())
    status PostStatus
    posts  Post[]
    @@allow('all', true)
}

model Post {
    id       Int        @id
    status   PostStatus
    authorId Int
    author   User       @relation(fields: [authorId], references: [id])
    @@allow('create', true)
    @@allow('read', <rule>)
}

Seed: one user with status: 'ACTIVE', three posts with DRAFT, ACTIVE, CANCELLED. Auth: { id: 1, status: 'ACTIVE' }.

Failing cases

1. Column on the right side of a comparison
  • ACTIVE == status
  • auth().status == status

Generated SQL is $1 = "Post"."status" with $1 = 'ACTIVE'. The mapper's binary-operation hook only handles a column reference on the left. SQLite returns no rows; PostgreSQL fails with invalid input value for enum "PostStatus": "ACTIVE".

2. Column vs. column through a relation
  • author.status == status

Generated SQL is (select CASE WHEN "$$t1"."status" = 'draft' THEN 'DRAFT' ... END from "User" as "$$t1" where ...) = "Post"."status". The mapper applies its mapped-back CASE projection inside the correlated subquery, so the left side yields the enum name while the right side is the raw database value. SQLite returns no rows; PostgreSQL fails with operator does not exist: text = "PostStatus".

Note that author.status == ACTIVE passes only because both sides happen to be names.

3. Enum array fields (PostgreSQL)

With statuses PostStatus[] on both User and Post:

  • ACTIVE in statuses
  • auth().status in statuses
  • status in auth().statuses
  • CANCELLED in auth().statuses

These go through the = ANY(...) / array-contains paths which the mapper does not handle, and some also hit PostgreSQL type errors (No function matches the given name and argument types).

Passing cases (for reference)

status == ACTIVE, status != CANCELLED, status == auth().status, status in [DRAFT, ACTIVE], !(status in [...]), status in PostStatus, author.status == ACTIVE, @@deny with status == CANCELLED, all four collection-predicate forms, and status in [...] in create/update/post-update/delete policies.

Discussion

Case 1 is a small addition to the mapper (handle the mirrored shape). Cases 2 and 3 are harder to fix by pattern-matching SQL: the mapper cannot distinguish a subquery used as a result column from one used as a comparison operand.

An alternative worth considering: make the policy transformer own the rule that everything inside policy SQL is in database representation, mapping enum literals and auth() values on the way in and never emitting mapped-back CASE projections in policy subqueries. A dedicated enum-reference expression kind in the generated TS schema (instead of a plain string literal) would make that mapping exact. The mapper would keep its current scope: CRUD arguments and result projections.

Ngôn ngữ chính
TypeScript
Star
2.9k
Fork
157
Merge trung bình
2 ngày 46 phút
Pull request đã merge (30 ngày)
17

Chuẩn bị môi trường

Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của zenstackhq/zenstack

Tất cả issue của zenstackhq/zenstack

Issue tương tự

Thêm issue về TypeScript

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.