Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(typegen): generate types for columns with json_schema constraint #814

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

phmasek
Copy link

@phmasek phmasek commented Oct 23, 2024

What kind of change does this PR introduce?

New feature to generate the types for JSON columns that are using jsonb_matches_schema check constraints.

Discussed here: https://github.com/orgs/supabase/discussions/30015

What is the current behavior?

The JSON columns are set to an overly generic structure:

string | number | boolean | {
    [key: string]: Json | undefined;
} | Json[]

What is the new behavior?

A JSON column that has a check constraint including the function jsonb_matches_schema or json_matches_schema gets a corresponding type generated based on that specific json schema.

Example

This SQL table:

CREATE TABLE public.memes (
	id serial NOT NULL PRIMARY KEY,
	name text NOT NULL,
	category INTEGER REFERENCES category(id),
	metadata jsonb,
	json_metadata json,
	free_metadata jsonb,
	created_at TIMESTAMP NOT NULL,
	status meme_status DEFAULT 'old'
);

ALTER TABLE public.memes ADD CONSTRAINT json_metadata_schema_check 
CHECK (
  (json_matches_schema('{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type": "object",
    "properties": {
      "popularity_score": {
        "type": "integer"
      },
      "name": {
        "type": "string"
      }
    },
    "additionalProperties": false
  }', json_metadata))
);

ALTER TABLE public.memes ADD CONSTRAINT metadata_schema_check 
CHECK (
  (jsonb_matches_schema('{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type": "object",
    "properties": {
      "popularity_score": {
        "type": "integer"
      },
      "name": {
        "type": "string"
      },
      "address": {
        "type": "object",
        "properties": {
          "city": {
            "type": "string"
          },
          "street": {
            "type": "string"
          }
        },
        "required": [
          "city",
          "street"
        ]
      }
    },
    "required": [
      "popoularity_score"
    ]
  }', metadata))
);

Receives this typing:

      ...
      memes: {
        Row: {
          category: number | null
          created_at: string
          free_metadata: Json | null
          id: number
          name: string
          status: Database["public"]["Enums"]["meme_status"] | null
          json_metadata:
            | Database["public"]["SchemaTypes"]["memes"]["json_metadata"]
            | null
          metadata:
            | Database["public"]["SchemaTypes"]["memes"]["metadata"]
            | null
        }
      ...

Where the path Database["public"]["SchemaTypes"]["memes"]["json_metadata"] leads to this:

SchemaTypes: {
  memes: {
    json_metadata: {
      popularity_score?: number
      name?: string
    }
    metadata: {
      popularity_score?: number
      name?: string
      address?: {
        city: string
        street: string
        [k: string]: unknown
      }
      [k: string]: unknown
    }
  }
}

Additional context

There is another pull request that address JSON columns in general to move away from the generic type mentioned above. However, that doesn't address the JSON columns that actually have check constraints to enforce a specific type structure.

@phmasek phmasek requested review from a team as code owners October 23, 2024 10:07
Copy link
Author

Choose a reason for hiding this comment

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

Copied the implementation from the supabase/postgres Dockerfile.

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.

1 participant