mirror of
https://github.com/supabase/supabase.git
synced 2026-06-12 08:29:15 +08:00
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Refactor + bug fixes (part of the SafeSql migration stack — PR 2 of 7, stacks on top of #45897). ## What is the current behavior? - `pgMeta.columns.create` and the table-editor SQL builder take column type as a string with array suffix and schema baked in (e.g. `'private.test_enum'`, `'int4[]'`). - The studio table-editor SQL emits the legacy schema-embedded `format` string for enums in non-public schemas, while the pg-meta columns SQL already returns the new shape (bare `format` + separate `format_schema`). The two queries disagree on how to represent the same column, surfacing as a false-positive type mismatch in the FK selector when both ends are an enum from a non-public schema. - The FK selector compares column types by `format` alone — same-named enums in different schemas appear equal, and arrays vs. scalars of the same base type pass the family check. - `displayColumnType` renders arrays as the raw `_typname` pg-meta emits (e.g. `_int4` instead of `int4[]`). ## What is the new behavior? **pg-meta** - Introduce `ColumnTypeRef` (`{ schema?, name, isArray? }`) for column type input, replacing the legacy string-with-array-suffix format. `pgMeta.columns.create` and the table-editor SQL builder consume the new shape. - Add `format_schema` to the column zod schema; pg-meta SQL emits the type's schema for the table editor's ColumnType dropdown. - `pgMeta.columns.create` returns a `SafeSqlFragment`. - Studio table-editor SQL now emits bare `format` + `format_schema`, matching pg-meta's columns SQL. **Studio** - `SafePostgresColumn`/`SafePostgresTable` extend the new `PG*` types (master dropped postgres-meta). - Pipe `ColumnTypeRef` through `SidePanelEditor` → `ColumnEditor` → `TableEditor`, along with the column-create mutation, table retrieve/list queries, and the `TableList`/`ColumnList` surfaces. - `displayColumnType` helper renders arrays as `type[]` (or `schema.type[]`) and handles non-implicit schemas. - FK selector now carries `sourceIsArray`/`targetIsArray` and compares the full `(format, format_schema, isArray)` triple. Family checks for numeric/text/uuid skip when either side is an array (FKs across array boundaries are never compatible). - Type-mismatch and type-notice alerts pass `isArray` to the display helper. - Bundle `Policies.utils` + `Policies.types` + `sql-policy-mutation`, `PolicyEditorModal`, and `SchemaGraph` here because `SidePanelEditor` consumes `acceptGeneratedPolicy`/`AcceptedGeneratedPolicy` — splitting requires temporary overloads with no architectural payoff. ## Additional context Part of the SafeSql migration stack. Stacks on top of #45897. ### Manual test checklist Surfaces touched by this PR — please exercise each: **Table editor** - [x] Create a new table with a mix of column types (scalar, array, enum, foreign key) - [x] Add a column to an existing table; verify the type dropdown lists scalars + arrays separately and shows schema-qualified names for non-public enums - [x] Edit an existing column's type (scalar ↔ array, switch between enums in different schemas) and save - [x] Verify enum types from a non-public schema (e.g. `private.my_enum`) display as `private.my_enum` in the column list **Foreign key selector** - [x] Open the FK selector for a column and pick a target column with a matching type — no mismatch warning - [x] Pick a target column whose type differs only by schema (two same-named enums in different schemas) — should show a type-mismatch alert - [x] Pick a target column where one side is an array and the other is a scalar of the same base type — should show a type-mismatch alert (no auto-cast across array boundary) - [x] When FK target sets the column type, verify `format_schema` and `isArray` are preserved on the source column - [x] Type-mismatch and type-notice alert messages render array types as `type[]` (not `_type`) **Column list / table list** - [x] Schema-qualified type names display correctly for columns whose type lives in a non-public schema - [x] Array columns display as `type[]` (or `schema.type[]`) **Policies (bundled due to import dependency)** - [x] Open the Policies page; create/edit/delete a row-level policy via the modal - [x] Generate a policy via the AI assistant and accept it through `SidePanelEditor` — verify the accepted policy lands in the editor correctly **Schema visualizer** - [x] Open the Schemas → Schema Visualizer page; verify it renders without type errors and shows tables/relationships <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Improvements** * Support for column types in non-public schemas and richer column type presentation (includes schema and array info). * Stronger SQL safety around policies and constraints; draft policy SQL is now promoted explicitly on save. * Improved foreign-key type validation and compatibility checks using enhanced type metadata. * **Tests** * Updated snapshots and tests to reflect new column metadata and SQL fragment handling. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45903) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
74 lines
1.8 KiB
TypeScript
74 lines
1.8 KiB
TypeScript
import { PGForeignTable, PGMaterializedView, PGView } from '@supabase/pg-meta'
|
|
|
|
import { ENTITY_TYPE } from '@/data/entity-types/entity-type-constants'
|
|
import type { SafePostgresTable } from '@/lib/postgres-types'
|
|
|
|
// [Joshen] We just need name, schema, description, rows, size, and the number of columns
|
|
// Just missing partitioned tables as missing pg-meta support
|
|
export const formatAllEntities = ({
|
|
tables = [],
|
|
views = [],
|
|
materializedViews = [],
|
|
foreignTables = [],
|
|
}: {
|
|
tables?: SafePostgresTable[]
|
|
views?: PGView[]
|
|
materializedViews?: PGMaterializedView[]
|
|
foreignTables?: PGForeignTable[]
|
|
}) => {
|
|
const formattedTables = tables.map((x) => {
|
|
return {
|
|
...x,
|
|
type: ENTITY_TYPE.TABLE as const,
|
|
rows: x.live_rows_estimate,
|
|
columns: x.columns ?? [],
|
|
}
|
|
})
|
|
|
|
const formattedViews = views.map((x) => {
|
|
return {
|
|
type: ENTITY_TYPE.VIEW as const,
|
|
id: x.id,
|
|
name: x.name,
|
|
comment: x.comment,
|
|
schema: x.schema,
|
|
rows: undefined,
|
|
size: undefined,
|
|
columns: x.columns ?? [],
|
|
}
|
|
})
|
|
|
|
const formattedMaterializedViews = materializedViews.map((x) => {
|
|
return {
|
|
type: ENTITY_TYPE.MATERIALIZED_VIEW as const,
|
|
id: x.id,
|
|
name: x.name,
|
|
comment: x.comment,
|
|
schema: x.schema,
|
|
rows: undefined,
|
|
size: undefined,
|
|
columns: x.columns ?? [],
|
|
}
|
|
})
|
|
|
|
const formattedForeignTables = foreignTables.map((x) => {
|
|
return {
|
|
type: ENTITY_TYPE.FOREIGN_TABLE as const,
|
|
id: x.id,
|
|
name: x.name,
|
|
comment: x.comment,
|
|
schema: x.schema,
|
|
rows: undefined,
|
|
size: undefined,
|
|
columns: x.columns ?? [],
|
|
}
|
|
})
|
|
|
|
return [
|
|
...formattedTables,
|
|
...formattedViews,
|
|
...formattedMaterializedViews,
|
|
...formattedForeignTables,
|
|
].sort((a, b) => a.name.localeCompare(b.name))
|
|
}
|