Skip to content

fix(orm): fix PostgreSQL type mismatch when @db.Uuid fields used in policy expressions#2532

Merged
ymc9 merged 6 commits intodevfrom
fix/2394-db-uuid-type-mismatch
Mar 31, 2026
Merged

fix(orm): fix PostgreSQL type mismatch when @db.Uuid fields used in policy expressions#2532
ymc9 merged 6 commits intodevfrom
fix/2394-db-uuid-type-mismatch

Conversation

@ymc9
Copy link
Copy Markdown
Member

@ymc9 ymc9 commented Mar 30, 2026

Summary

Fixes #2394. Two related PostgreSQL errors ("operator does not exist: uuid = text") when @db.Uuid fields are involved in policy expressions:

  • before() in post-update policies: the $before VALUES table was casting UUID ID columns to text instead of uuid, causing the JOIN condition to fail.
  • Policy field comparisons: comparing a @db.Uuid column against a plain String field or an auth() value (which always arrives as a text parameter) caused a type mismatch.

Changes

packages/orm/src/client/crud/dialects/postgresql.ts

  • getSqlType now checks @db.* field attributes first, returning the exact native SQL type (e.g. uuid) instead of the generic ZModel base type (text) — fixes the VALUES table cast for before().
  • New buildComparison override detects when one operand has a @db.* native type and the other doesn't, and casts the native-typed side back to its base ZModel SQL type to align comparison types.

packages/orm/src/client/crud/dialects/base-dialect.ts

  • New buildComparison virtual method with a default passthrough implementation for other dialects (SQLite, MySQL) where this is not an issue.

packages/plugins/policy/src/expression-transformer.ts

  • _binary now routes non-null comparisons through dialect.buildComparison, keeping all database-specific casting logic inside the dialect layer.

Test plan

  • tests/regression/test/issue-2394.test.ts — two new PostgreSQL regression tests covering both fixed scenarios

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Fixed comparison behavior so UUID and string fields compare reliably, preventing incorrect policy allow/deny outcomes.
  • Refactor

    • Comparison and casting logic updated to respect explicit native-type overrides for PostgreSQL and to cast only overridden sides when needed.
    • Policy expression handling now delegates comparisons through the query dialect for consistent SQL generation.
  • Tests

    • Added regression tests covering UUID/string comparisons, multi-hop relation comparisons, auth-based policies, and related scenarios.

…olicy expressions (#2394)

Two related bugs where `@db.Uuid` fields caused "operator does not exist: uuid = text" errors:

1. `before()` in post-update policies: VALUES table was casting UUID ID fields to
   `text` instead of `uuid`, breaking the `$before` JOIN condition.
2. Policy expressions comparing a `@db.Uuid` column against a plain `String` field or
   an `auth()` value (which always arrives as a text parameter).

Fix (1): `getSqlType` in the PostgreSQL dialect now checks `@db.*` field attributes
first, returning the exact native type (e.g. `uuid`) rather than the generic ZModel
base type (e.g. `text`).

Fix (2): A new `buildComparison` dialect hook lets the PostgreSQL dialect detect when
one operand carries a `@db.*` native type override and the other doesn't, and casts
the native-typed side back to its base ZModel SQL type so the comparison types align.
The policy plugin calls this hook instead of building the `BinaryOperationNode` directly,
keeping all database-specific logic in the dialect layer.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude
Copy link
Copy Markdown
Contributor

claude bot commented Mar 30, 2026

Claude finished @ymc9's task —— View job


PR Review Complete ✅

Reviewing PR #2532: PostgreSQL UUID type mismatch fix

Code Quality & Best Practices ⭐

Excellent work overall! The implementation follows clean coding principles:

  • Clear separation of concerns: Database-specific logic stays in the PostgreSQL dialect
  • Extensible design: Base dialect provides virtual method for other databases
  • Comprehensive mapping: Complete @db.* attribute to SQL type mapping
  • Proper error handling: Graceful fallbacks and clear logic flow

Technical Implementation 🔧

PostgreSQL Dialect (postgresql.ts:455-474)

The buildComparison override is well-designed:

  • Correctly detects when one operand has native @db.* type and the other doesn't
  • Casts the native type back to base ZModel type for compatibility
  • Handles both left/right operand scenarios cleanly
  • Falls back to parent implementation appropriately

Base Dialect Interface (base-dialect.ts:1498-1506)

The virtual method addition is properly architected:

  • Default passthrough implementation for non-PostgreSQL dialects
  • Clean interface that allows database-specific overrides
  • Maintains backward compatibility

Expression Transformer (expression-transformer.ts:268-275)

The routing through dialect.buildComparison is architecturally sound:

  • Removes hardcoded operator transformation
  • Provides field definitions for context-aware type handling
  • Maintains separation between expression logic and database specifics

Security Assessment 🔒

No security concerns identified:

  • ✅ Uses parameterized SQL casts, preventing injection
  • ✅ Validates field definitions before use
  • ✅ No exposure of sensitive data or credentials

Performance Considerations ⚡

Minimal performance impact:

  • ✅ Type checking uses simple attribute iteration (O(n) where n = attribute count)
  • ✅ Casts only applied when necessary (type mismatch detected)
  • ✅ No additional database roundtrips introduced

Test Coverage 📊

Comprehensive regression tests:

Suggestion: Test Enhancement

Consider uncommenting the denied update test in the first test case:

// updating with the same status should be denied
await expect(db.item.update({ where: { id: updated.id }, data: { status: 'published' } })).rejects.toThrow();

Minor Code Quality Notes 📝

  1. Import Ordering: Minor cleanup in base-dialect.ts:27 (moves import to maintain alphabetical order)
  2. Code Formatting: Some line length improvements for readability
  3. Type Safety: All type assertions properly handled with fallbacks

Architecture Strengths 🏗️

  • Database Abstraction: Keeps PostgreSQL-specific logic isolated
  • Extensibility: Other databases can implement similar fixes if needed
  • Backwards Compatibility: No breaking changes to existing APIs
  • Type Safety: Leverages TypeScript properly throughout

Recommendation: APPROVE

This is a high-quality fix that:

  • Solves the specific PostgreSQL UUID type mismatch issue elegantly
  • Follows established patterns and architectural principles
  • Includes comprehensive test coverage
  • Has minimal performance impact and no security concerns

The implementation demonstrates strong understanding of both the ZenStack codebase architecture and PostgreSQL type system requirements.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 30, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Base dialect gained a concrete comparison builder; PostgreSQL dialect maps @db.* attributes to native SQL types and selectively casts operands; policy expression transformer delegates binary comparisons to the dialect with resolved FieldDefs; regression tests for UUID/auth comparisons were added.

Changes

Cohort / File(s) Summary
Base dialect
packages/orm/src/client/crud/dialects/base-dialect.ts
Added concrete buildComparison(left, _leftFieldDef, op, right, _rightFieldDef) that returns a SqlBool via the dialect expression builder; minor import/formatting tweaks.
PostgreSQL dialect
packages/orm/src/client/crud/dialects/postgresql.ts
Added dbAttributeToSqlTypeMap; getSqlType accepts optional field attributes; new resolveFieldSqlType tracks @db.* origin; overridden buildComparison casts overridden sides back to base ZModel SQL type when needed; VALUES-table casts use attribute-aware types.
Policy expression transformer
packages/plugins/policy/src/expression-transformer.ts
Binary comparison path now resolves FieldDefs for both operands (supports relation-chain member access) and calls dialect.buildComparison(...) with wrapped expressions instead of emitting a generic binary node; removed old operator helper.
Tests (regression)
tests/regression/test/issue-2394.test.ts
Added regression suite covering UUID (@db.Uuid) comparisons with auth() across post-update, value-vs-UUID, single-hop and multi-hop relation comparisons, and auth-scoped checks.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I nibble through schemas, casting strings to uuid light,
I hop the dialect fences, making comparisons right.
Policies cheer in moonbeam, queries sleep tight,
Tests nibble the edges — carrots glowing bright. 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: fixing a PostgreSQL type mismatch when @db.Uuid fields are used in policy expressions, which is the core objective.
Linked Issues check ✅ Passed The PR implementation comprehensively addresses all objectives from #2394: it fixes value casting for @db.Uuid fields in policy expressions and handles type mismatches in binary comparisons by adding dialect-specific casting logic.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the @db.Uuid type mismatch issue; refactoring imports, adding buildComparison methods, and extending getFieldDefFromFieldRef are all necessary to support the core fix.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/2394-db-uuid-type-mismatch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/orm/src/client/crud/dialects/postgresql.ts`:
- Around line 455-474: The current buildComparison only checks presence of `@db`.*
attributes; instead resolve the actual SQL type names for left and right
(extract the `@db`.* attribute value when present, e.g.
attribute.name.slice('@db.'.length), and fallback to
this.getSqlType(fieldDef.type) for base types) and compare those resolved SQL
type strings; if they differ and at least one side used a `@db`.* override, cast
the overridden side back to its base SQL type using this.eb.cast(...,
sql.raw(this.getSqlType(...))) before calling super.buildComparison so
mismatched native/native or native/implicit comparisons (e.g. uuid vs text) are
normalized.

In `@packages/plugins/policy/src/expression-transformer.ts`:
- Around line 268-274: The comparison lookup must use the correct type depending
on the operand context: change the two calls to
getFieldDefFromFieldRef(normalizedLeft, context.modelOrType) and
getFieldDefFromFieldRef(normalizedRight, context.modelOrType) so they resolve
against context.thisType when the ref is a "this" reference (e.g. this.foo) and
keep using context.modelOrType for direct fields and for before().foo
expressions; update the logic around normalizedLeft/normalizedRight detection
(look for "this" prefix or before() pattern) and pass the appropriate type into
getFieldDefFromFieldRef before calling dialect.buildComparison/ExpressionWrapper
so the FieldDef preserves native-type info for buildComparison.

In `@tests/regression/test/issue-2394.test.ts`:
- Around line 30-46: The test currently only compares two fields; add a
regression test that compares the `@db.Uuid` field to an auth() value so
transformAuthBinary's path is exercised: change the model policy to use
@@allow('all', id == auth()) (reference @@allow and auth()), use
createPolicyTestClient to create the test DB client (reference
createPolicyTestClient), generate a UUID (reference randomUUID/newId) and ensure
the create/update calls supply the same auth value in the request/session
context the test harness expects so the auth() side is typed as the native UUID
and the create/update assertions (db.foo.create and db.foo.update) still resolve
truthily; this will catch regressions where auth() loses native-type metadata
(reference transformAuthBinary).
- Around line 22-27: Uncomment the deny-path assertion so the test verifies the
post-update deny behavior: re-enable the lines that call expect(db.item.update({
where: { id: updated.id }, data: { status: 'published' } })).rejects.toThrow();
(i.e., keep the earlier successful update via db.item.update to 'published',
then call db.item.update again with the same status and assert it throws) to
ensure the policy check that compares before().status to the new status is
actually exercised.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 723b55a4-db83-4d5e-94c5-f95221aa692c

📥 Commits

Reviewing files that changed from the base of the PR and between 85d8b6b and cb7e60d.

📒 Files selected for processing (4)
  • packages/orm/src/client/crud/dialects/base-dialect.ts
  • packages/orm/src/client/crud/dialects/postgresql.ts
  • packages/plugins/policy/src/expression-transformer.ts
  • tests/regression/test/issue-2394.test.ts

…ison

Instead of casting based solely on presence of @db.* attributes, resolve
the effective SQL type for each side (native type from @db.* or base ZModel
type as fallback), then only cast when the types actually differ. This avoids
unnecessary casts for @db.Text vs String (both `text`) and correctly handles
two differing native types (e.g. @db.Uuid vs @db.Citext).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude
Copy link
Copy Markdown
Contributor

claude bot commented Mar 31, 2026

Claude finished @ymc9's task —— View job


PR Review: PostgreSQL UUID Type Mismatch Fix

Reviewing PR #2532 that fixes PostgreSQL type mismatches when @db.Uuid fields are used in policy expressions.

Todo List

  • Read and analyze all changed files
  • Assess code quality and implementation approach
  • Evaluate test coverage and regression tests
  • Check for potential bugs and edge cases
  • Review performance and security considerations
  • Provide comprehensive feedback

Overall Assessment ⭐

This is a well-architected solution to a specific PostgreSQL type system issue. The implementation demonstrates strong understanding of database dialect differences and follows good separation of concerns by keeping PostgreSQL-specific logic isolated.

Code Quality & Best Practices ✅

Excellent Architecture

  • Clean separation of concerns: Database-specific logic stays in PostgreSQL dialect
  • Extensible design: Base dialect provides virtual method for other databases to override if needed
  • Comprehensive type mapping: Complete coverage of all PostgreSQL @db.* attributes
  • Proper fallback handling: Graceful degradation when field definitions are missing

Strong Implementation Details

  • Type safety: All type assertions are properly handled with null checks
  • Clear naming: resolveFieldSqlType and buildComparison methods are descriptive
  • Good documentation: Clear comments explaining the purpose and behavior

Technical Deep Dive 🔧

PostgreSQL Dialect Changes (postgresql.ts:455-489)

Strengths:

  • The resolveFieldSqlType helper correctly separates concerns between type resolution and comparison logic
  • Comprehensive mapping covers all PostgreSQL native types (UUID, CITEXT, INET, etc.)
  • Logic correctly casts native types back to base ZModel types for compatibility

Areas of Concern:
The current implementation has a critical gap identified by CodeRabbit - it only checks for presence of @db.* attributes, not actual type compatibility. For example:

// This would still fail in PostgreSQL:
@db.Uuid field compared to @db.Text field
// Because both have native types but they're incompatible

Base Dialect Interface (base-dialect.ts:1498-1506)

Well designed:

  • Clean virtual method that allows database-specific overrides
  • Default passthrough implementation maintains backward compatibility
  • Proper parameter naming and documentation

Expression Transformer (expression-transformer.ts:268-275)

Architectural improvement:

  • Removes hardcoded operator transformation logic
  • Provides field definitions for context-aware type handling
  • Maintains clean separation between expression logic and database specifics

Potential issue: Field resolution always uses context.modelOrType, which may not be correct for this.field references or before().field expressions in all contexts.

Test Coverage 📊

Comprehensive Regression Tests ✅

Test 1 (lines 6-28): Tests before().status == status comparison in post-update policies

  • ✅ Covers the VALUES table casting issue
  • ⚠️ Missing verification: Commented out denial test doesn't verify the policy actually works

Test 2 (lines 30-47): Tests field-to-field comparison (id == id1)

  • ✅ Covers basic UUID-to-String comparison
  • ⚠️ Missing coverage: No test for auth() value comparison (the original issue scenario)

Suggested Test Enhancements

  1. Uncomment denial test to ensure policy logic is actually working
  2. Add auth() comparison test to cover transformAuthBinary path
  3. Add native-to-native type tests (e.g., @db.Uuid vs @db.Text)

Security Assessment 🔒

No security concerns identified:

  • Uses parameterized SQL casts, preventing injection
  • Validates field definitions before use
  • No exposure of sensitive data or credentials
  • Type casting logic is safe and doesn't introduce vulnerabilities

Performance Considerations ⚡

Minimal performance impact:

  • Type checking uses simple attribute iteration (O(n) where n = attribute count)
  • Casts only applied when necessary (type mismatch detected)
  • No additional database roundtrips introduced
  • Map lookups are O(1) for the attribute-to-type mapping

Critical Issues to Address 🚨

1. Incomplete Type Resolution Logic

Location: postgresql.ts:480

The current logic only checks if sides have @db.* attributes but doesn't verify type compatibility:

// Current logic - insufficient:
if (leftResolved.sqlType !== rightResolved.sqlType && (leftResolved.hasDbOverride || rightResolved.hasDbOverride))

// Should resolve actual SQL type names and compare those

2. Context-Sensitive Field Resolution

Location: expression-transformer.ts:268-269

Field lookups need to consider the expression context:

  • this.field should resolve against context.thisType
  • before().field should resolve against context.modelOrType
  • Direct fields should resolve against context.modelOrType

3. Missing Test Coverage

Location: issue-2394.test.ts:27 and issue-2394.test.ts:46

  • Denial test is commented out - policy verification incomplete
  • No test for auth() comparison (the original reported scenario)

Recommendations 📋

Priority 1: Fix Type Resolution Logic

Enhance buildComparison to resolve and compare actual SQL type names rather than just checking for attribute presence.

Priority 2: Enhance Test Coverage

  • Uncomment the denial assertion in test 1
  • Add test case comparing @db.Uuid field to auth() value
  • Consider adding native-to-native type mismatch tests

Priority 3: Improve Field Resolution Context

Update expression transformer to pass appropriate type context for different reference patterns.

Final Verdict 🎯

This PR provides a solid foundation for fixing PostgreSQL UUID type mismatches, with excellent architectural patterns and comprehensive type mapping. However, the type resolution logic needs refinement to handle all edge cases, and test coverage should be expanded to ensure robustness.

Recommendation: Request changes to address the type resolution gaps and test coverage improvements before merging.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/orm/src/client/crud/dialects/postgresql.ts (1)

455-466: Edge case: unmapped @db.* attributes return sqlType: undefined with hasDbOverride: true.

If a @db.* attribute exists but isn't in dbAttributeToSqlTypeMap (e.g., @db.Money), line 463 returns { sqlType: undefined, hasDbOverride: true }. This works in practice—buildComparison will cast the field to its base ZModel type—but the combination of undefined type with a true override flag is semantically confusing.

Consider adding a fallback or a comment clarifying this behavior:

📝 Optional: clarify fallback for unmapped attributes
     private resolveFieldSqlType(fieldDef: FieldDef | undefined): { sqlType: string | undefined; hasDbOverride: boolean } {
         if (!fieldDef) {
             return { sqlType: undefined, hasDbOverride: false };
         }
         const dbAttr = fieldDef.attributes?.find((a) => a.name.startsWith('@db.'));
         if (dbAttr) {
-            return { sqlType: PostgresCrudDialect.dbAttributeToSqlTypeMap[dbAttr.name], hasDbOverride: true };
+            const mappedType = PostgresCrudDialect.dbAttributeToSqlTypeMap[dbAttr.name];
+            // If the `@db`.* attribute isn't in our map, fall back to base ZModel type
+            // but still mark hasDbOverride so buildComparison knows to cast if needed
+            return { sqlType: mappedType ?? this.getSqlType(fieldDef.type), hasDbOverride: true };
         }
         return { sqlType: this.getSqlType(fieldDef.type), hasDbOverride: false };
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/orm/src/client/crud/dialects/postgresql.ts` around lines 455 - 466,
The resolveFieldSqlType function currently sets hasDbOverride=true even when a
`@db`.* attribute isn't mapped, which is confusing; update resolveFieldSqlType so
that when dbAttr exists but
PostgresCrudDialect.dbAttributeToSqlTypeMap[dbAttr.name] is undefined you fall
back to this.getSqlType(fieldDef.type) and return hasDbOverride:false (i.e.,
treat unmapped attributes as no override), keeping references to
resolveFieldSqlType, PostgresCrudDialect.dbAttributeToSqlTypeMap, getSqlType and
FieldDef so the change is made in the same method and keeps buildComparison
behavior unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/orm/src/client/crud/dialects/postgresql.ts`:
- Around line 455-466: The resolveFieldSqlType function currently sets
hasDbOverride=true even when a `@db`.* attribute isn't mapped, which is confusing;
update resolveFieldSqlType so that when dbAttr exists but
PostgresCrudDialect.dbAttributeToSqlTypeMap[dbAttr.name] is undefined you fall
back to this.getSqlType(fieldDef.type) and return hasDbOverride:false (i.e.,
treat unmapped attributes as no override), keeping references to
resolveFieldSqlType, PostgresCrudDialect.dbAttributeToSqlTypeMap, getSqlType and
FieldDef so the change is made in the same method and keeps buildComparison
behavior unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ee7a05b9-b9bf-495a-afc8-74e33e4ddc01

📥 Commits

Reviewing files that changed from the base of the PR and between cb7e60d and 455e6f2.

📒 Files selected for processing (1)
  • packages/orm/src/client/crud/dialects/postgresql.ts



Exercises the transformAuthBinary path where `id == auth()` expands to
`id == auth().id`. The auth value is always emitted as a text parameter
regardless of the auth model's @db.Uuid attribute, so this catches
regressions where the uuid/text type mismatch is reintroduced.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude
Copy link
Copy Markdown
Contributor

claude bot commented Mar 31, 2026

Claude finished @ymc9's task —— View job


PR Review: PostgreSQL UUID Type Mismatch Fix

Reviewing PR #2532 that fixes PostgreSQL type mismatches when @db.Uuid fields are used in policy expressions.

Todo List

  • Read and analyze all changed files
  • Assess code quality and implementation approach
  • Evaluate test coverage and regression tests
  • Check for potential bugs and edge cases
  • Review performance and security considerations
  • Provide comprehensive feedback

Overall Assessment ⭐

This is a well-architected solution to a specific PostgreSQL type system issue. The implementation demonstrates strong understanding of database dialect differences and follows good separation of concerns by keeping PostgreSQL-specific logic isolated.

Code Quality & Best Practices ✅

Excellent Architecture

  • Clean separation of concerns: Database-specific logic stays in PostgreSQL dialect
  • Extensible design: Base dialect provides virtual method for other databases to override if needed
  • Comprehensive type mapping: Complete coverage of all PostgreSQL @db.* attributes
  • Proper fallback handling: Graceful degradation when field definitions are missing

Strong Implementation Details

  • Type safety: All type assertions are properly handled with null checks
  • Clear naming: resolveFieldSqlType and buildComparison methods are descriptive
  • Good documentation: Clear comments explaining the purpose and behavior

Technical Deep Dive 🔧

PostgreSQL Dialect Changes (postgresql.ts:455-489)

Strengths:

  • The resolveFieldSqlType helper correctly separates concerns between type resolution and comparison logic
  • Comprehensive mapping covers all PostgreSQL native types (UUID, CITEXT, INET, etc.)
  • Logic correctly casts native types back to base ZModel types for compatibility

Areas of Concern:
The current implementation has a critical gap identified by CodeRabbit - it only checks for presence of @db.* attributes, not actual type compatibility. For example:

// This would still fail in PostgreSQL:
@db.Uuid field compared to @db.Text field
// Because both have native types but they're incompatible

Base Dialect Interface (base-dialect.ts:1498-1506)

Well designed:

  • Clean virtual method that allows database-specific overrides
  • Default passthrough implementation maintains backward compatibility
  • Proper parameter naming and documentation

Expression Transformer (expression-transformer.ts:268-275)

Architectural improvement:

  • Removes hardcoded operator transformation logic
  • Provides field definitions for context-aware type handling
  • Maintains clean separation between expression logic and database specifics

Potential issue: Field resolution always uses context.modelOrType, which may not be correct for this.field references or before().field expressions in all contexts.

Test Coverage 📊

Comprehensive Regression Tests ✅

Test 1 (lines 6-30): Tests before().status == status comparison in post-update policies

  • ✅ Covers the VALUES table casting issue
  • Great improvement: The denial test is now properly enabled and working

Test 2 (lines 32-49): Tests field-to-field comparison (id == id1)

  • ✅ Covers basic UUID-to-String comparison

Test 3 (lines 51-72): Tests @db.Uuid field to auth() comparison

  • Excellent addition: Covers the original issue scenario with transformAuthBinary
  • ✅ Uses realistic authentication flow with $setAuth()

Test Quality Assessment

The test suite now comprehensively covers all three scenarios mentioned in the original issue:

  1. before() comparisons in post-update policies
  2. ✅ Field-to-field UUID vs String comparisons
  3. ✅ UUID field vs auth() value comparisons

Security Assessment 🔒

No security concerns identified:

  • Uses parameterized SQL casts, preventing injection
  • Validates field definitions before use
  • No exposure of sensitive data or credentials
  • Type casting logic is safe and doesn't introduce vulnerabilities

Performance Considerations ⚡

Minimal performance impact:

  • Type checking uses simple attribute iteration (O(n) where n = attribute count)
  • Casts only applied when necessary (type mismatch detected)
  • No additional database roundtrips introduced
  • Map lookups are O(1) for the attribute-to-type mapping

Critical Issues to Address 🚨

1. Incomplete Type Resolution Logic

Location: postgresql.ts:480

The current logic only checks if sides have @db.* attributes but doesn't verify type compatibility:

// Current logic - insufficient:
if (leftResolved.sqlType !== rightResolved.sqlType && (leftResolved.hasDbOverride || rightResolved.hasDbOverride))

// Should resolve actual SQL type names and compare those

This means comparisons between different native types (e.g., @db.Uuid vs @db.Text) would still fail.

2. Context-Sensitive Field Resolution

Location: expression-transformer.ts:268-269

Field lookups need to consider the expression context:

  • this.field should resolve against context.thisType
  • before().field should resolve against context.modelOrType
  • Direct fields should resolve against context.modelOrType

3. Edge Case: Unmapped Attributes

Location: postgresql.ts:463

If a @db.* attribute exists but isn't in the map, it returns sqlType: undefined with hasDbOverride: true, which is semantically confusing.

Recommendations 📋

Priority 1: Fix Type Resolution Logic

Enhance buildComparison to resolve and compare actual SQL type names rather than just checking for attribute presence.

Priority 2: Improve Field Resolution Context

Update expression transformer to pass appropriate type context for different reference patterns.

Priority 3: Handle Unmapped Attributes

Consider falling back to base SQL type for unmapped @db.* attributes rather than undefined.

Final Verdict 🎯

This PR provides a solid foundation for fixing PostgreSQL UUID type mismatches, with excellent architectural patterns and comprehensive type mapping. The test coverage is now excellent with all three scenarios properly tested.

However, the type resolution logic needs refinement to handle native-to-native type mismatches and field resolution context issues.

Recommendation: Request changes to address the type resolution gaps identified by CodeRabbit before merging.


@claude
Copy link
Copy Markdown
Contributor

claude bot commented Mar 31, 2026

Claude finished @ymc9's task —— View job


PR Review: PostgreSQL UUID Type Mismatch Fix

Reviewing PR #2532 that fixes PostgreSQL type mismatches when @db.Uuid fields are used in policy expressions.

Todo List

  • Read and analyze all changed files
  • Assess code quality and implementation approach
  • Evaluate test coverage and regression tests
  • Check for potential bugs and edge cases
  • Review performance and security considerations
  • Provide comprehensive feedback

Overall Assessment ⭐

This is a well-architected solution to a specific PostgreSQL type system issue. The implementation demonstrates strong understanding of database dialect differences and follows good separation of concerns by keeping PostgreSQL-specific logic isolated.

Code Quality & Best Practices ✅

Excellent Architecture

  • Clean separation of concerns: Database-specific logic stays in PostgreSQL dialect
  • Extensible design: Base dialect provides virtual method for other databases to override if needed
  • Comprehensive type mapping: Complete coverage of all PostgreSQL @db.* attributes
  • Proper fallback handling: Graceful degradation when field definitions are missing

Strong Implementation Details

  • Type safety: All type assertions are properly handled with null checks
  • Clear naming: resolveFieldSqlType and buildComparison methods are descriptive
  • Good documentation: Clear comments explaining the purpose and behavior

Technical Deep Dive 🔧

PostgreSQL Dialect Changes (postgresql.ts:455-489)

Strengths:

  • The resolveFieldSqlType helper correctly separates concerns between type resolution and comparison logic
  • Comprehensive mapping covers all PostgreSQL native types (UUID, CITEXT, INET, etc.)
  • Logic correctly casts native types back to base ZModel types for compatibility

Areas of Concern:
The current implementation has a critical gap identified by CodeRabbit - it only checks for presence of @db.* attributes, not actual type compatibility. For example:

// This would still fail in PostgreSQL:
@db.Uuid field compared to @db.Text field
// Because both have native types but they're incompatible

Base Dialect Interface (base-dialect.ts:1498-1506)

Well designed:

  • Clean virtual method that allows database-specific overrides
  • Default passthrough implementation maintains backward compatibility
  • Proper parameter naming and documentation

Expression Transformer (expression-transformer.ts:268-275)

Architectural improvement:

  • Removes hardcoded operator transformation logic
  • Provides field definitions for context-aware type handling
  • Maintains clean separation between expression logic and database specifics

Potential issue: Field resolution always uses context.modelOrType, which may not be correct for this.field references or before().field expressions in all contexts.

Test Coverage 📊

Comprehensive Regression Tests ✅

Test 1 (lines 6-30): Tests before().status == status comparison in post-update policies

  • ✅ Covers the VALUES table casting issue
  • Great improvement: The denial test is now properly enabled and working

Test 2 (lines 32-49): Tests field-to-field comparison (id == id1)

  • ✅ Covers basic UUID-to-String comparison

Test 3 (lines 51-72): Tests @db.Uuid field to auth() comparison

  • Excellent addition: Covers the original issue scenario with transformAuthBinary
  • ✅ Uses realistic authentication flow with $setAuth()

Test Quality Assessment

The test suite now comprehensively covers all three scenarios mentioned in the original issue:

  1. before() comparisons in post-update policies
  2. ✅ Field-to-field UUID vs String comparisons
  3. ✅ UUID field vs auth() value comparisons

Security Assessment 🔒

No security concerns identified:

  • Uses parameterized SQL casts, preventing injection
  • Validates field definitions before use
  • No exposure of sensitive data or credentials
  • Type casting logic is safe and doesn't introduce vulnerabilities

Performance Considerations ⚡

Minimal performance impact:

  • Type checking uses simple attribute iteration (O(n) where n = attribute count)
  • Casts only applied when necessary (type mismatch detected)
  • No additional database roundtrips introduced
  • Map lookups are O(1) for the attribute-to-type mapping

Critical Issues to Address 🚨

1. Incomplete Type Resolution Logic

Location: postgresql.ts:480

The current logic only checks if sides have @db.* attributes but doesn't verify type compatibility:

// Current logic - insufficient:
if (leftResolved.sqlType !== rightResolved.sqlType && (leftResolved.hasDbOverride || rightResolved.hasDbOverride))

// Should resolve actual SQL type names and compare those

This means comparisons between different native types (e.g., @db.Uuid vs @db.Text) would still fail.

2. Context-Sensitive Field Resolution

Location: expression-transformer.ts:268-269

Field lookups need to consider the expression context:

  • this.field should resolve against context.thisType
  • before().field should resolve against context.modelOrType
  • Direct fields should resolve against context.modelOrType

3. Edge Case: Unmapped Attributes

Location: postgresql.ts:463

If a @db.* attribute exists but isn't in the map, it returns sqlType: undefined with hasDbOverride: true, which is semantically confusing.

Recommendations 📋

Priority 1: Fix Type Resolution Logic

Enhance buildComparison to resolve and compare actual SQL type names rather than just checking for attribute presence.

Priority 2: Improve Field Resolution Context

Update expression transformer to pass appropriate type context for different reference patterns.

Priority 3: Handle Unmapped Attributes

Consider falling back to base SQL type for unmapped @db.* attributes rather than undefined.

Final Verdict 🎯

This PR provides a solid foundation for fixing PostgreSQL UUID type mismatches, with excellent architectural patterns and comprehensive type mapping. The test coverage is now excellent with all three scenarios properly tested.

However, the type resolution logic needs refinement to handle native-to-native type mismatches and field resolution context issues.

Recommendation: Request changes to address the type resolution gaps identified by CodeRabbit before merging.


… casting

Extended getFieldDefFromFieldRef to handle:
- `this.foo` references resolving against thisType instead of modelOrType,
  so native-type info is preserved in collection-predicate contexts where
  the two differ.
- Single- and multi-hop relation field access (e.g. `owner.tag`,
  `org.owner.token`): walk the relation chain and return the terminal
  field's FieldDef so buildComparison can detect @db.* type mismatches
  and cast accordingly (e.g. "operator does not exist: uuid = text").

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude
Copy link
Copy Markdown
Contributor

claude bot commented Mar 31, 2026

Claude finished @ymc9's task —— View job


PR Review: PostgreSQL UUID Type Mismatch Fix

Reviewing PR #2532 that fixes PostgreSQL type mismatches when @db.Uuid fields are used in policy expressions.

Todo List

  • Read and analyze all changed files
  • Assess code quality and implementation approach
  • Evaluate test coverage and regression tests
  • Check for potential bugs and edge cases
  • Review performance and security considerations
  • Provide comprehensive feedback

Overall Assessment ⭐

This is a well-architected solution to a specific PostgreSQL type system issue. The implementation demonstrates strong understanding of database dialect differences and follows good separation of concerns by keeping PostgreSQL-specific logic isolated.

Code Quality & Best Practices ✅

Excellent Architecture

  • Clean separation of concerns: Database-specific logic stays in PostgreSQL dialect
  • Extensible design: Base dialect provides virtual method for other databases to override if needed
  • Comprehensive type mapping: Complete coverage of all PostgreSQL @db.* attributes
  • Proper fallback handling: Graceful degradation when field definitions are missing

Strong Implementation Details

  • Type safety: All type assertions are properly handled with null checks
  • Clear naming: resolveFieldSqlType and buildComparison methods are descriptive
  • Good documentation: Clear comments explaining the purpose and behavior

Technical Deep Dive 🔧

PostgreSQL Dialect Changes (postgresql.ts:455-489)

Strengths:

  • The resolveFieldSqlType helper correctly separates concerns between type resolution and comparison logic
  • Comprehensive mapping covers all PostgreSQL native types (UUID, CITEXT, INET, etc.)
  • Logic correctly casts native types back to base ZModel types for compatibility

Areas of Concern:
The current implementation has a critical gap identified by CodeRabbit - it only checks for presence of @db.* attributes, not actual type compatibility. For example:

// This would still fail in PostgreSQL:
@db.Uuid field compared to @db.Text field
// Because both have native types but they're incompatible

Base Dialect Interface (base-dialect.ts:1498-1506)

Well designed:

  • Clean virtual method that allows database-specific overrides
  • Default passthrough implementation maintains backward compatibility
  • Proper parameter naming and documentation

Expression Transformer (expression-transformer.ts:268-279)

Architectural improvement:

  • Removes hardcoded operator transformation logic
  • Provides field definitions for context-aware type handling
  • Maintains clean separation between expression logic and database specifics

Great context resolution fix:

  • Correctly handles this.field references vs direct field references
  • Uses context.thisType for this. references and context.modelOrType for others

Test Coverage 📊

Comprehensive Regression Tests ✅

Test 1 (lines 6-30): Tests before().status == status comparison in post-update policies

  • ✅ Covers the VALUES table casting issue
  • Great improvement: The denial test is now properly enabled and working

Test 2 (lines 32-49): Tests field-to-field comparison (id == id1)

  • ✅ Covers basic UUID-to-String comparison

Test 3 (lines 51-84): Tests @db.Uuid field to related field comparison (single-hop)

  • Excellent addition: Covers correlated subquery scenarios

Test 4 (lines 86-132): Tests multi-hop relation chain with @db.Uuid fields

  • ✅ Covers complex org.owner.token == tokenRef scenarios

Test 5 (lines 134-155): Tests @db.Uuid field to auth() comparison

  • Excellent addition: Covers the original issue scenario with transformAuthBinary
  • ✅ Uses realistic authentication flow with $setAuth()

Test Quality Assessment

The test suite now comprehensively covers all scenarios mentioned in the original issue:

  1. before() comparisons in post-update policies
  2. ✅ Field-to-field UUID vs String comparisons
  3. ✅ UUID field vs auth() value comparisons
  4. ✅ Single-hop and multi-hop relation chains
  5. ✅ Correlated subquery scenarios

Security Assessment 🔒

No security concerns identified:

  • Uses parameterized SQL casts, preventing injection
  • Validates field definitions before use
  • No exposure of sensitive data or credentials
  • Type casting logic is safe and doesn't introduce vulnerabilities

Performance Considerations ⚡

Minimal performance impact:

  • Type checking uses simple attribute iteration (O(n) where n = attribute count)
  • Casts only applied when necessary (type mismatch detected)
  • No additional database roundtrips introduced
  • Map lookups are O(1) for the attribute-to-type mapping

Critical Issues to Address 🚨

1. Incomplete Type Resolution Logic

Location: postgresql.ts:480

The current logic only checks if sides have @db.* attributes but doesn't verify type compatibility:

// Current logic - insufficient:
if (leftResolved.sqlType !== rightResolved.sqlType && (leftResolved.hasDbOverride || rightResolved.hasDbOverride))

// Should resolve actual SQL type names and compare those

This means comparisons between different native types (e.g., @db.Uuid vs @db.Text) would still fail.

2. Edge Case: Unmapped Attributes

Location: postgresql.ts:463

If a @db.* attribute exists but isn't in the map, it returns sqlType: undefined with hasDbOverride: true, which is semantically confusing.

Recommendations 📋

Priority 1: Fix Type Resolution Logic

Enhance buildComparison to resolve and compare actual SQL type names rather than just checking for attribute presence.

Priority 2: Handle Unmapped Attributes

Consider falling back to base SQL type for unmapped @db.* attributes rather than undefined.

Final Verdict 🎯

This PR provides a solid foundation for fixing PostgreSQL UUID type mismatches, with excellent architectural patterns and comprehensive type mapping. The test coverage is now excellent with all scenarios properly tested.

However, the type resolution logic needs refinement to handle native-to-native type mismatches identified by CodeRabbit.

Recommendation: Request changes to address the type resolution gaps before merging.


Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
packages/plugins/policy/src/expression-transformer.ts (1)

268-279: ⚠️ Potential issue | 🟠 Major

Field metadata still disappears for before(), binding, and multi-hop this operands.

Lines 270-279 only switch away from modelOrType for direct this.*, and Lines 1005-1017 only walk chains when the receiver is a plain field. before().ownerId, binding.ownerId, and this.owner.id still reach buildComparison(...) with undefined FieldDefs, so PostgreSQL can still miss the native @db.* cast and reproduce the same uuid = text failure on those supported expression forms. Please resolve the receiver model from the full comparison context before walking the member chain.

Also applies to: 996-1017

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/plugins/policy/src/expression-transformer.ts` around lines 268 -
279, The field metadata loss happens because you only switch to context.thisType
for direct `this.*` receivers and only walk member chains when the immediate
receiver is a plain field; update the comparison resolution to first resolve the
root receiver and its model from the whole member chain (e.g., inspect the full
normalizedLeft/normalizedRight member chain to find if the ultimate root is
`this`, `binding`, `before`, or a model field) and then call
getFieldDefFromFieldRef with that resolved model so buildComparison never
receives undefined FieldDef; adjust the logic around
ExpressionUtils.isMember/ExpressionUtils.isThis checks and the code that
currently sets leftModel/rightModel (and the member-walking block around the
996-1017 area) to walk chains for multi-hop `this.owner.id`, `before().ownerId`,
and `binding.ownerId` and derive the correct FieldDef.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@packages/plugins/policy/src/expression-transformer.ts`:
- Around line 268-279: The field metadata loss happens because you only switch
to context.thisType for direct `this.*` receivers and only walk member chains
when the immediate receiver is a plain field; update the comparison resolution
to first resolve the root receiver and its model from the whole member chain
(e.g., inspect the full normalizedLeft/normalizedRight member chain to find if
the ultimate root is `this`, `binding`, `before`, or a model field) and then
call getFieldDefFromFieldRef with that resolved model so buildComparison never
receives undefined FieldDef; adjust the logic around
ExpressionUtils.isMember/ExpressionUtils.isThis checks and the code that
currently sets leftModel/rightModel (and the member-walking block around the
996-1017 area) to walk chains for multi-hop `this.owner.id`, `before().ownerId`,
and `binding.ownerId` and derive the correct FieldDef.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d204cd18-25b5-4d49-94f4-5eb204591dc0

📥 Commits

Reviewing files that changed from the base of the PR and between 10ac9f8 and 1094d85.

📒 Files selected for processing (2)
  • packages/plugins/policy/src/expression-transformer.ts
  • tests/regression/test/issue-2394.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/regression/test/issue-2394.test.ts

…model string

Move the this.foo → thisType / else → modelOrType selection inside
getFieldDefFromFieldRef so callers don't need to compute a leftModel/rightModel
intermediate before each call.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude
Copy link
Copy Markdown
Contributor

claude bot commented Mar 31, 2026

Claude finished @ymc9's task —— View job


PR Review: PostgreSQL UUID Type Mismatch Fix

Reviewing PR #2532 that fixes PostgreSQL type mismatches when @db.Uuid fields are used in policy expressions.

Todo List

  • Read and analyze all changed files
  • Assess code quality and implementation approach
  • Evaluate test coverage and regression tests
  • Check for potential bugs and edge cases
  • Review performance and security considerations
  • Provide comprehensive feedback

Overall Assessment ⭐

This is a well-architected solution to a specific PostgreSQL type system issue. The implementation demonstrates strong understanding of database dialect differences and follows good separation of concerns by keeping PostgreSQL-specific logic isolated.

Code Quality & Best Practices ✅

Excellent Architecture

  • Clean separation of concerns: Database-specific logic stays in PostgreSQL dialect
  • Extensible design: Base dialect provides virtual method for other databases to override if needed
  • Comprehensive type mapping: Complete coverage of all PostgreSQL @db.* attributes
  • Proper fallback handling: Graceful degradation when field definitions are missing

Strong Implementation Details

  • Type safety: All type assertions are properly handled with null checks
  • Clear naming: resolveFieldSqlType and buildComparison methods are descriptive
  • Good documentation: Clear comments explaining the purpose and behavior

Technical Deep Dive 🔧

PostgreSQL Dialect Changes (postgresql.ts:455-489)

Strengths:

  • The resolveFieldSqlType helper correctly separates concerns between type resolution and comparison logic
  • Comprehensive mapping covers all PostgreSQL native types (UUID, CITEXT, INET, etc.)
  • Logic correctly casts native types back to base ZModel types for compatibility

Areas of Concern:
The current implementation has a critical gap identified by CodeRabbit - it only checks for presence of @db.* attributes, not actual type compatibility. For example:

// This would still fail in PostgreSQL:
@db.Uuid field compared to @db.Text field
// Because both have native types but they're incompatible

Base Dialect Interface (base-dialect.ts:1498-1506)

Well designed:

  • Clean virtual method that allows database-specific overrides
  • Default passthrough implementation maintains backward compatibility
  • Proper parameter naming and documentation

Expression Transformer (expression-transformer.ts:268-279)

Architectural improvement:

  • Removes hardcoded operator transformation logic
  • Provides field definitions for context-aware type handling
  • Maintains clean separation between expression logic and database specifics

Great context resolution fix:

  • Correctly handles this.field references vs direct field references
  • Uses context.thisType for this. references and context.modelOrType for others

Test Coverage 📊

Comprehensive Regression Tests ✅

Test 1 (lines 6-30): Tests before().status == status comparison in post-update policies

  • ✅ Covers the VALUES table casting issue
  • Great improvement: The denial test is now properly enabled and working

Test 2 (lines 32-49): Tests field-to-field comparison (id == id1)

  • ✅ Covers basic UUID-to-String comparison

Test 3 (lines 51-84): Tests @db.Uuid field to related field comparison (single-hop)

  • Excellent addition: Covers correlated subquery scenarios

Test 4 (lines 86-132): Tests multi-hop relation chain with @db.Uuid fields

  • ✅ Covers complex org.owner.token == tokenRef scenarios

Test 5 (lines 134-155): Tests @db.Uuid field to auth() comparison

  • Excellent addition: Covers the original issue scenario with transformAuthBinary
  • ✅ Uses realistic authentication flow with $setAuth()

Test Quality Assessment

The test suite now comprehensively covers all scenarios mentioned in the original issue:

  1. before() comparisons in post-update policies
  2. ✅ Field-to-field UUID vs String comparisons
  3. ✅ UUID field vs auth() value comparisons
  4. ✅ Single-hop and multi-hop relation chains
  5. ✅ Correlated subquery scenarios

Security Assessment 🔒

No security concerns identified:

  • Uses parameterized SQL casts, preventing injection
  • Validates field definitions before use
  • No exposure of sensitive data or credentials
  • Type casting logic is safe and doesn't introduce vulnerabilities

Performance Considerations ⚡

Minimal performance impact:

  • Type checking uses simple attribute iteration (O(n) where n = attribute count)
  • Casts only applied when necessary (type mismatch detected)
  • No additional database roundtrips introduced
  • Map lookups are O(1) for the attribute-to-type mapping

Critical Issues to Address 🚨

1. Incomplete Type Resolution Logic

Location: postgresql.ts:480

The current logic only checks if sides have @db.* attributes but doesn't verify type compatibility:

// Current logic - insufficient:
if (leftResolved.sqlType !== rightResolved.sqlType && (leftResolved.hasDbOverride || rightResolved.hasDbOverride))

// Should resolve actual SQL type names and compare those

This means comparisons between different native types (e.g., @db.Uuid vs @db.Text) would still fail.

2. Edge Case: Unmapped Attributes

Location: postgresql.ts:463

If a @db.* attribute exists but isn't in the map, it returns sqlType: undefined with hasDbOverride: true, which is semantically confusing.

Recommendations 📋

Priority 1: Fix Type Resolution Logic

Enhance buildComparison to resolve and compare actual SQL type names rather than just checking for attribute presence.

Priority 2: Handle Unmapped Attributes

Consider falling back to base SQL type for unmapped @db.* attributes rather than undefined.

Final Verdict 🎯

This PR provides a solid foundation for fixing PostgreSQL UUID type mismatches, with excellent architectural patterns and comprehensive type mapping. The test coverage is now excellent with all scenarios properly tested.

However, the type resolution logic needs refinement to handle native-to-native type mismatches identified by CodeRabbit.

Recommendation: Request changes to address the type resolution gaps before merging.


@ymc9 ymc9 merged commit 4686720 into dev Mar 31, 2026
8 checks passed
@ymc9 ymc9 deleted the fix/2394-db-uuid-type-mismatch branch March 31, 2026 01:39
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: policy check fails with "operator does not exist: text = uuid" when auth() field has @db.Uuid

1 participant