From 6a47684084751bf33ce50bd0d03ecab165e9c52e Mon Sep 17 00:00:00 2001 From: avallete Date: Mon, 27 Oct 2025 16:32:56 +0100 Subject: [PATCH 1/2] fix(postgrest): add incoming major 14 support --- .../src/PostgrestTransformBuilder.ts | 3 ++- .../src/select-query-parser/result.ts | 4 +--- .../postgrest-js/src/types/feature-flags.ts | 17 +++++++++++++++++ packages/core/postgrest-js/src/types/types.ts | 3 --- 4 files changed, 20 insertions(+), 7 deletions(-) create mode 100644 packages/core/postgrest-js/src/types/feature-flags.ts diff --git a/packages/core/postgrest-js/src/PostgrestTransformBuilder.ts b/packages/core/postgrest-js/src/PostgrestTransformBuilder.ts index cf94aea82..52b554199 100644 --- a/packages/core/postgrest-js/src/PostgrestTransformBuilder.ts +++ b/packages/core/postgrest-js/src/PostgrestTransformBuilder.ts @@ -1,8 +1,9 @@ import PostgrestBuilder from './PostgrestBuilder' import PostgrestFilterBuilder, { InvalidMethodError } from './PostgrestFilterBuilder' import { GetResult } from './select-query-parser/result' -import { CheckMatchingArrayTypes, MaxAffectedEnabled } from './types/types' +import { CheckMatchingArrayTypes } from './types/types' import { ClientServerOptions, GenericSchema } from './types/common/common' +import type { MaxAffectedEnabled } from './types/feature-flags' export default class PostgrestTransformBuilder< ClientOptions extends ClientServerOptions, diff --git a/packages/core/postgrest-js/src/select-query-parser/result.ts b/packages/core/postgrest-js/src/select-query-parser/result.ts index e2c980b61..22207afdf 100644 --- a/packages/core/postgrest-js/src/select-query-parser/result.ts +++ b/packages/core/postgrest-js/src/select-query-parser/result.ts @@ -24,9 +24,7 @@ import { ResolveRelationship, SelectQueryError, } from './utils' - -export type SpreadOnManyEnabled = - PostgrestVersion extends `13${string}` ? true : false +import type { SpreadOnManyEnabled } from '../types/feature-flags' /** * Main entry point for constructing the result type of a PostgREST query. diff --git a/packages/core/postgrest-js/src/types/feature-flags.ts b/packages/core/postgrest-js/src/types/feature-flags.ts new file mode 100644 index 000000000..5f5ea061b --- /dev/null +++ b/packages/core/postgrest-js/src/types/feature-flags.ts @@ -0,0 +1,17 @@ +type IsPostgrest13 = + PostgrestVersion extends `13${string}` ? true : false +type IsPostgrest14 = + PostgrestVersion extends `14${string}` ? true : false + +type IsPostgrestVersionGreaterThan12 = + IsPostgrest13 extends true + ? true + : IsPostgrest14 extends true + ? true + : false + +export type MaxAffectedEnabled = + IsPostgrestVersionGreaterThan12 extends true ? true : false + +export type SpreadOnManyEnabled = + IsPostgrestVersionGreaterThan12 extends true ? true : false diff --git a/packages/core/postgrest-js/src/types/types.ts b/packages/core/postgrest-js/src/types/types.ts index 842810ece..29e545410 100644 --- a/packages/core/postgrest-js/src/types/types.ts +++ b/packages/core/postgrest-js/src/types/types.ts @@ -35,9 +35,6 @@ export type DatabaseWithOptions = options: Options } -export type MaxAffectedEnabled = - PostgrestVersion extends `13${string}` ? true : false - // https://twitter.com/mattpocockuk/status/1622730173446557697 export type Prettify = { [K in keyof T]: T[K] } & {} From dec347ca3b441b80931c0423af0c3d108fc4e649 Mon Sep 17 00:00:00 2001 From: avallete Date: Mon, 27 Oct 2025 16:48:37 +0100 Subject: [PATCH 2/2] chore(postgrest): bump 13 to 14 --- .../postgrest-js/test/db/docker-compose.yml | 4 +- .../core/postgrest-js/test/index.test-d.ts | 2 +- .../postgrest-js/test/max-affected.test.ts | 52 +++++++++---------- .../relationships-spread-operations.test.ts | 16 +++--- ...pes.generated-with-options-postgrest14.ts} | 2 +- ...ypes.override-with-options-postgrest14.ts} | 2 +- 6 files changed, 39 insertions(+), 39 deletions(-) rename packages/core/postgrest-js/test/{types.generated-with-options-postgrest13.ts => types.generated-with-options-postgrest14.ts} (99%) rename packages/core/postgrest-js/test/{types.override-with-options-postgrest13.ts => types.override-with-options-postgrest14.ts} (99%) diff --git a/packages/core/postgrest-js/test/db/docker-compose.yml b/packages/core/postgrest-js/test/db/docker-compose.yml index 7d2818653..271bafbf6 100644 --- a/packages/core/postgrest-js/test/db/docker-compose.yml +++ b/packages/core/postgrest-js/test/db/docker-compose.yml @@ -1,7 +1,7 @@ # docker-compose.yml services: - rest13: - image: postgrest/postgrest:v13.0.0 + rest14: + image: postgrest/postgrest:v14.0 ports: - '3001:3000' environment: diff --git a/packages/core/postgrest-js/test/index.test-d.ts b/packages/core/postgrest-js/test/index.test-d.ts index 6310ee69b..93d46e9aa 100644 --- a/packages/core/postgrest-js/test/index.test-d.ts +++ b/packages/core/postgrest-js/test/index.test-d.ts @@ -3,7 +3,7 @@ import { PostgrestClient, PostgrestError } from '../src/index' import { Prettify } from '../src/types/types' import { Json } from '../src/select-query-parser/types' import { Database } from './types.override' -import { Database as DatabaseWithOptions } from './types.override-with-options-postgrest13' +import { Database as DatabaseWithOptions } from './types.override-with-options-postgrest14' const REST_URL = 'http://localhost:3000' const postgrest = new PostgrestClient(REST_URL) diff --git a/packages/core/postgrest-js/test/max-affected.test.ts b/packages/core/postgrest-js/test/max-affected.test.ts index 0e06006d3..77ab50be0 100644 --- a/packages/core/postgrest-js/test/max-affected.test.ts +++ b/packages/core/postgrest-js/test/max-affected.test.ts @@ -1,14 +1,14 @@ import { PostgrestClient } from '../src/index' import { Database } from './types.override' -import { Database as DatabasePostgrest13 } from './types.override-with-options-postgrest13' +import { Database as DatabasePostgrest14 } from './types.override-with-options-postgrest14' import { expectType, TypeEqual } from './types' import { InvalidMethodError } from '../src/PostgrestFilterBuilder' import { z } from 'zod' import { RequiredDeep } from 'type-fest' -const REST_URL_13 = 'http://localhost:3001' -const postgrest13 = new PostgrestClient(REST_URL_13) -const postgrest12 = new PostgrestClient(REST_URL_13) +const REST_URL_14 = 'http://localhost:3001' +const postgrest14 = new PostgrestClient(REST_URL_14) +const postgrest12 = new PostgrestClient(REST_URL_14) const MessageRowSchema = z.object({ channel_id: z.number(), @@ -28,22 +28,22 @@ describe('maxAffected', () => { expectType>(resUpdate) }) test('types: maxAffected should show type warning on non update / delete', async () => { - const resSelect = postgrest13.from('messages').select('*').maxAffected(10) - const resInsert = postgrest13 + const resSelect = postgrest14.from('messages').select('*').maxAffected(10) + const resInsert = postgrest14 .from('messages') .insert({ message: 'foo', username: 'supabot', channel_id: 1 }) .maxAffected(10) - const resUpsert = postgrest13 + const resUpsert = postgrest14 .from('messages') .upsert({ id: 3, message: 'foo', username: 'supabot', channel_id: 2 }) .maxAffected(10) - const resUpdate = postgrest13 + const resUpdate = postgrest14 .from('messages') .update({ channel_id: 2 }) .eq('message', 'foo') .maxAffected(1) .select() - const resDelete = postgrest13 + const resDelete = postgrest14 .from('messages') .delete() .eq('message', 'foo') @@ -70,14 +70,14 @@ describe('maxAffected', () => { test('update should fail when maxAffected is exceeded', async () => { // First create multiple rows - await postgrest13.from('messages').insert([ + await postgrest14.from('messages').insert([ { message: 'test1', username: 'supabot', channel_id: 1 }, { message: 'test1', username: 'supabot', channel_id: 1 }, { message: 'test1', username: 'supabot', channel_id: 1 }, ]) // Try to update all rows with maxAffected=2 - const result = await postgrest13 + const result = await postgrest14 .from('messages') .update({ message: 'updated' }) .eq('message', 'test1') @@ -88,17 +88,17 @@ describe('maxAffected', () => { expect(error?.code).toBe('PGRST124') // cleanup - await postgrest13.from('messages').delete().eq('message', 'test1') + await postgrest14.from('messages').delete().eq('message', 'test1') }) test('update should succeed when within maxAffected limit', async () => { // First create a single row - await postgrest13 + await postgrest14 .from('messages') .insert([{ message: 'test2', username: 'supabot', channel_id: 1 }]) // Try to update with maxAffected=2 - const { data, error } = await postgrest13 + const { data, error } = await postgrest14 .from('messages') .update({ message: 'updated' }) .eq('message', 'test2') @@ -116,19 +116,19 @@ describe('maxAffected', () => { expect(data?.[0].message).toBe('updated') // cleanup - await postgrest13.from('messages').delete().eq('message', 'updated') + await postgrest14.from('messages').delete().eq('message', 'updated') }) test('delete should fail when maxAffected is exceeded', async () => { // First create multiple rows - await postgrest13.from('messages').insert([ + await postgrest14.from('messages').insert([ { message: 'test3', username: 'supabot', channel_id: 1 }, { message: 'test3', username: 'supabot', channel_id: 1 }, { message: 'test3', username: 'supabot', channel_id: 1 }, ]) // Try to delete all rows with maxAffected=2 - const { error } = await postgrest13 + const { error } = await postgrest14 .from('messages') .delete() .eq('message', 'test3') @@ -138,17 +138,17 @@ describe('maxAffected', () => { expect(error?.code).toBe('PGRST124') // cleanup - await postgrest13.from('messages').delete().eq('message', 'test3') + await postgrest14.from('messages').delete().eq('message', 'test3') }) test('delete should succeed when within maxAffected limit', async () => { // First create a single row - await postgrest13 + await postgrest14 .from('messages') .insert([{ message: 'test4', username: 'supabot', channel_id: 1 }]) // Try to delete with maxAffected=2 - const { data, error } = await postgrest13 + const { data, error } = await postgrest14 .from('messages') .delete() .eq('message', 'test4') @@ -162,9 +162,9 @@ describe('maxAffected', () => { test('should be able to use .maxAffected with setof records returning rpc', async () => { // First create a user that will be returned by the RPC - await postgrest13.from('users').insert([{ username: 'testuser', status: 'ONLINE' }]) + await postgrest14.from('users').insert([{ username: 'testuser', status: 'ONLINE' }]) // Call the RPC function that returns a set of records - const { data, error } = await postgrest13 + const { data, error } = await postgrest14 .rpc('set_users_offline', { name_param: 'testuser' }) .maxAffected(1) .select() @@ -182,19 +182,19 @@ describe('maxAffected', () => { ]) // cleanup - await postgrest13.from('users').delete().eq('username', 'testuser') + await postgrest14.from('users').delete().eq('username', 'testuser') }) test('should fail when rpc returns more results than maxAffected', async () => { // First create multiple users that will be returned by the RPC - await postgrest13.from('users').insert([ + await postgrest14.from('users').insert([ { username: 'testuser1', status: 'ONLINE' }, { username: 'testuser2', status: 'ONLINE' }, { username: 'testuser3', status: 'ONLINE' }, ]) // Call the RPC function that returns a set of records - const { data, error } = await postgrest13 + const { data, error } = await postgrest14 .rpc('set_users_offline', { name_param: 'testuser%' }) .maxAffected(1) .select() @@ -204,6 +204,6 @@ describe('maxAffected', () => { expect(data).toBeNull() // cleanup - await postgrest13.from('users').delete().in('username', ['testuser1', 'testuser2', 'testuser3']) + await postgrest14.from('users').delete().in('username', ['testuser1', 'testuser2', 'testuser3']) }) }) diff --git a/packages/core/postgrest-js/test/relationships-spread-operations.test.ts b/packages/core/postgrest-js/test/relationships-spread-operations.test.ts index 642fa9c7c..ec9a50c1c 100644 --- a/packages/core/postgrest-js/test/relationships-spread-operations.test.ts +++ b/packages/core/postgrest-js/test/relationships-spread-operations.test.ts @@ -1,14 +1,14 @@ import { PostgrestClient } from '../src/index' import { Database } from './types.override' -import { Database as DatabaseWithOptions13 } from './types.override-with-options-postgrest13' +import { Database as DatabaseWithOptions13 } from './types.override-with-options-postgrest14' import { expectType, TypeEqual } from './types' import { z } from 'zod' const REST_URL = 'http://localhost:3000' const postgrest = new PostgrestClient(REST_URL) -const REST_URL_13 = 'http://localhost:3001' -const postgrest13 = new PostgrestClient(REST_URL_13) -const postgrest13FromDatabaseTypes = new PostgrestClient(REST_URL_13) +const REST_URL_14 = 'http://localhost:3001' +const postgrest14 = new PostgrestClient(REST_URL_14) +const postgrest14FromDatabaseTypes = new PostgrestClient(REST_URL_14) test('select with aggregate count and spread', async () => { const res = await postgrest @@ -326,8 +326,8 @@ test('select with spread on nested relation', async () => { ExpectedSchema.parse(res.data) }) -test('select spread on many relation postgrest13', async () => { - const res = await postgrest13 +test('select spread on many relation postgrest14', async () => { + const res = await postgrest14 .from('channels') .select('channel_id:id, ...messages(id, message)') .limit(1) @@ -360,8 +360,8 @@ test('select spread on many relation postgrest13', async () => { ExpectedSchema.parse(res.data) }) -test('select spread on many relation postgrest13FromDatabaseTypes', async () => { - const res = await postgrest13FromDatabaseTypes +test('select spread on many relation postgrest14FromDatabaseTypes', async () => { + const res = await postgrest14FromDatabaseTypes .from('channels') .select('channel_id:id, ...messages(id, message)') .limit(1) diff --git a/packages/core/postgrest-js/test/types.generated-with-options-postgrest13.ts b/packages/core/postgrest-js/test/types.generated-with-options-postgrest14.ts similarity index 99% rename from packages/core/postgrest-js/test/types.generated-with-options-postgrest13.ts rename to packages/core/postgrest-js/test/types.generated-with-options-postgrest14.ts index f497c2e7d..e00c340af 100644 --- a/packages/core/postgrest-js/test/types.generated-with-options-postgrest13.ts +++ b/packages/core/postgrest-js/test/types.generated-with-options-postgrest14.ts @@ -5,7 +5,7 @@ export type Database = OriginalDatabase & { // This is a dummy non existent schema to allow automatically passing down options // to the instanciated client at type levels from the introspected database __InternalSupabase: { - PostgrestVersion: '13.0.12' + PostgrestVersion: '14.0' } } diff --git a/packages/core/postgrest-js/test/types.override-with-options-postgrest13.ts b/packages/core/postgrest-js/test/types.override-with-options-postgrest14.ts similarity index 99% rename from packages/core/postgrest-js/test/types.override-with-options-postgrest13.ts rename to packages/core/postgrest-js/test/types.override-with-options-postgrest14.ts index ab7999ab8..976e87f01 100644 --- a/packages/core/postgrest-js/test/types.override-with-options-postgrest13.ts +++ b/packages/core/postgrest-js/test/types.override-with-options-postgrest14.ts @@ -1,4 +1,4 @@ -import type { Database as GeneratedDatabase } from './types.generated-with-options-postgrest13' +import type { Database as GeneratedDatabase } from './types.generated-with-options-postgrest14' import { MergeDeep } from 'type-fest' export type CustomUserDataType = {