From 02ae920d93162eb5ae2ece901d624af91205e250 Mon Sep 17 00:00:00 2001 From: avallete Date: Mon, 27 Oct 2025 14:00:14 +0100 Subject: [PATCH] test(postgrest): add partitionned tables computed field tests --- .../core/postgrest-js/test/db/00-schema.sql | 44 ++++++ .../postgrest-js/test/db/01-dummy-data.sql | 11 +- .../postgrest-js/test/db/docker-compose.yml | 2 +- .../test/embeded_functions_join.test.ts | 133 ++++++++++++++++++ .../core/postgrest-js/test/types.generated.ts | 95 +++++++++++++ 5 files changed, 283 insertions(+), 2 deletions(-) diff --git a/packages/core/postgrest-js/test/db/00-schema.sql b/packages/core/postgrest-js/test/db/00-schema.sql index d3ac6748b..a3700f627 100644 --- a/packages/core/postgrest-js/test/db/00-schema.sql +++ b/packages/core/postgrest-js/test/db/00-schema.sql @@ -59,6 +59,13 @@ CREATE TABLE public.messages ( ALTER TABLE public.messages REPLICA IDENTITY FULL; -- Send "previous data" to supabase COMMENT ON COLUMN public.messages.data IS 'For unstructured data and prototyping.'; +-- USERS AUDIT +CREATE TABLE public.users_audit ( + id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + created_at timestamptz DEFAULT now(), + previous_value bigint +); + -- SELF REFERENCING TABLE CREATE TABLE public.collections ( id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, @@ -357,3 +364,40 @@ ROWS 1 AS $$ SELECT * FROM public.user_profiles WHERE username = user_row.username LIMIT 1; $$; + +-- Function that return the created_ago computed field +CREATE OR REPLACE FUNCTION "public"."created_ago" ("public"."users_audit") RETURNS numeric LANGUAGE "sql" +SET + "search_path" TO '' +AS $_$ + SELECT ROUND(EXTRACT(EPOCH FROM (NOW() - $1.created_at))); +$_$; + +-- Create a partitioned table for testing computed fields on partitioned tables +CREATE TABLE public.events ( + id bigint generated by default as identity, + created_at timestamptz default now(), + event_type text, + data jsonb, + primary key (id, created_at) +) partition by range (created_at); + +-- Create partitions for the events table +CREATE TABLE public.events_2024 PARTITION OF public.events +FOR VALUES FROM ('2024-01-01') TO ('2025-01-01'); + +CREATE TABLE public.events_2025 PARTITION OF public.events +FOR VALUES FROM ('2025-01-01') TO ('2026-01-01'); + +-- Insert some test data +INSERT INTO public.events (created_at, event_type, data) +VALUES + ('2024-06-15', 'login', '{"user": "alice"}'), + ('2025-03-20', 'logout', '{"user": "bob"}'); + +-- Function that returns computed field for partitioned table +CREATE OR REPLACE FUNCTION "public"."days_since_event" ("public"."events") RETURNS numeric LANGUAGE "sql" +SET + "search_path" TO '' AS $_$ + SELECT ROUND(EXTRACT(EPOCH FROM (NOW() - $1.created_at)) / 86400); +$_$; \ No newline at end of file diff --git a/packages/core/postgrest-js/test/db/01-dummy-data.sql b/packages/core/postgrest-js/test/db/01-dummy-data.sql index 6580bcf2b..39b5638f6 100644 --- a/packages/core/postgrest-js/test/db/01-dummy-data.sql +++ b/packages/core/postgrest-js/test/db/01-dummy-data.sql @@ -119,4 +119,13 @@ VALUES (5, 3), -- Booking for Beachfront Inn (6, 1), -- Third booking for Sunset Resort (7, NULL), -- Another booking with no hotel - (8, 4); -- Booking for hotel with null name \ No newline at end of file + (8, 4); -- Booking for hotel with null name + +-- Insert users audit +INSERT INTO public.users_audit (id, previous_value) +VALUES + (1, 42), + (2, 42), + (3, 42), + (4, 42), + (5, 42); \ No newline at end of file diff --git a/packages/core/postgrest-js/test/db/docker-compose.yml b/packages/core/postgrest-js/test/db/docker-compose.yml index 7d2818653..2db0a4367 100644 --- a/packages/core/postgrest-js/test/db/docker-compose.yml +++ b/packages/core/postgrest-js/test/db/docker-compose.yml @@ -39,7 +39,7 @@ services: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres pgmeta: - image: supabase/postgres-meta:v0.92.0 + image: supabase/postgres-meta:v0.93.1 ports: - '8080:8080' environment: diff --git a/packages/core/postgrest-js/test/embeded_functions_join.test.ts b/packages/core/postgrest-js/test/embeded_functions_join.test.ts index 1a69cae91..465fe3514 100644 --- a/packages/core/postgrest-js/test/embeded_functions_join.test.ts +++ b/packages/core/postgrest-js/test/embeded_functions_join.test.ts @@ -1225,4 +1225,137 @@ describe('embeded functions select', () => { expectType>(true) ExpectedSchema.parse(res.data) }) + + // test select the created_ago embeded function + test('select the created_ago embeded function', async () => { + const res = await postgrest.from('users_audit').select('id, created_ago') + expect(res).toMatchInlineSnapshot(` + Object { + "count": null, + "data": Array [ + Object { + "created_ago": 7, + "id": 1, + }, + Object { + "created_ago": 7, + "id": 2, + }, + Object { + "created_ago": 7, + "id": 3, + }, + Object { + "created_ago": 7, + "id": 4, + }, + Object { + "created_ago": 7, + "id": 5, + }, + ], + "error": null, + "status": 200, + "statusText": "OK", + } + `) + let result: Exclude + const ExpectedSchema = z.array( + z.object({ + id: z.number(), + created_ago: z.number().nullable(), + }) + ) + let expected: z.infer + expectType>(true) + expectType>(true) + ExpectedSchema.parse(res.data) + const use_rpc_call = await postgrest.rpc('created_ago', { + // @ts-expect-error - id is not a parameter of the created_ago function + id: 1, + }) + expect(use_rpc_call).toMatchInlineSnapshot(` + Object { + "count": null, + "data": null, + "error": Object { + "code": "PGRST202", + "details": "Searched for the function public.created_ago with parameter id or with a single unnamed json/jsonb parameter, but no matches were found in the schema cache.", + "hint": null, + "message": "Could not find the function public.created_ago(id) in the schema cache", + }, + "status": 404, + "statusText": "Not Found", + } + `) + let result_rpc: Exclude + expectType< + TypeEqual< + typeof result_rpc, + { + error: true + } & 'the function public.created_ago with parameter or with a single unnamed json/jsonb parameter, but no matches were found in the schema cache' + > + >(true) + }) + // Test the days_since_event embeded function over partitioned table + test('select the days_since_event embeded function over partitioned table', async () => { + const res = await postgrest.from('events').select('id, days_since_event') + expect(res).toMatchInlineSnapshot(` + Object { + "count": null, + "data": Array [ + Object { + "days_since_event": 500, + "id": 1, + }, + Object { + "days_since_event": 222, + "id": 2, + }, + ], + "error": null, + "status": 200, + "statusText": "OK", + } + `) + let result: Exclude + const ExpectedSchema = z.array( + z.object({ + id: z.number(), + days_since_event: z.number().nullable(), + }) + ) + let expected: z.infer + expectType>(true) + expectType>(true) + ExpectedSchema.parse(res.data) + const use_rpc_call = await postgrest.rpc('days_since_event', { + // @ts-expect-error - id is not a parameter of the days_since_event function + id: 1, + }) + expect(use_rpc_call).toMatchInlineSnapshot(` + Object { + "count": null, + "data": null, + "error": Object { + "code": "PGRST202", + "details": "Searched for the function public.days_since_event with parameter id or with a single unnamed json/jsonb parameter, but no matches were found in the schema cache.", + "hint": null, + "message": "Could not find the function public.days_since_event(id) in the schema cache", + }, + "status": 404, + "statusText": "Not Found", + } + `) + let result_rpc: Exclude + expectType< + TypeEqual< + typeof result_rpc, + { + error: true + } & 'the function public.days_since_event with parameter or with a single unnamed json/jsonb parameter, but no matches were found in the schema cache' + > + >(true) + }) }) diff --git a/packages/core/postgrest-js/test/types.generated.ts b/packages/core/postgrest-js/test/types.generated.ts index 373ccea56..c0a97fb90 100644 --- a/packages/core/postgrest-js/test/types.generated.ts +++ b/packages/core/postgrest-js/test/types.generated.ts @@ -275,6 +275,70 @@ export type Database = { } Relationships: [] } + events: { + Row: { + created_at: string + data: Json | null + event_type: string | null + id: number + days_since_event: number | null + } + Insert: { + created_at?: string + data?: Json | null + event_type?: string | null + id?: number + } + Update: { + created_at?: string + data?: Json | null + event_type?: string | null + id?: number + } + Relationships: [] + } + events_2024: { + Row: { + created_at: string + data: Json | null + event_type: string | null + id: number + } + Insert: { + created_at?: string + data?: Json | null + event_type?: string | null + id: number + } + Update: { + created_at?: string + data?: Json | null + event_type?: string | null + id?: number + } + Relationships: [] + } + events_2025: { + Row: { + created_at: string + data: Json | null + event_type: string | null + id: number + } + Insert: { + created_at?: string + data?: Json | null + event_type?: string | null + id: number + } + Update: { + created_at?: string + data?: Json | null + event_type?: string | null + id?: number + } + Relationships: [] + } hotel: { Row: { id: number @@ -488,6 +552,25 @@ export type Database = { } Relationships: [] } + users_audit: { + Row: { + created_at: string | null + id: number + previous_value: number | null + created_ago: number | null + } + Insert: { + created_at?: string | null + id?: number + previous_value?: number | null + } + Update: { + created_at?: string | null + id?: number + previous_value?: number | null + } + Relationships: [] + } } Views: { active_users: { @@ -589,6 +672,18 @@ export type Database = { error: true } & 'the function public.blurb_message with parameter or with a single unnamed json/jsonb parameter, but no matches were found in the schema cache' } + created_ago: { + Args: { '': Database['public']['Tables']['users_audit']['Row'] } + Returns: { + error: true + } & 'the function public.created_ago with parameter or with a single unnamed json/jsonb parameter, but no matches were found in the schema cache' + } + days_since_event: { + Args: { '': Database['public']['Tables']['events']['Row'] } + Returns: { + error: true + } & 'the function public.days_since_event with parameter or with a single unnamed json/jsonb parameter, but no matches were found in the schema cache' + } function_returning_row: { Args: never Returns: {