diff --git a/package.json b/package.json index 0e051492..933528a2 100644 --- a/package.json +++ b/package.json @@ -21,12 +21,13 @@ "scripts": { "clean": "rimraf dist docs/v2", "format": "prettier --write \"{src,test}/**/*.ts\"", + "format:check": "prettier --check \"{src,test}/**/*.ts\"", "build": "run-s clean format build:*", "build:main": "tsc -p tsconfig.json", "build:module": "tsc -p tsconfig.module.json", "docs": "typedoc src/index.ts --out docs/v2", "docs:json": "typedoc --json docs/v2/spec.json --excludeExternals src/index.ts", - "test": "run-s test:types db:clean db:run test:run db:clean", + "test": "run-s format:check test:types db:clean db:run test:run db:clean", "test:run": "jest --runInBand", "test:update": "run-s db:clean db:run && jest --runInBand --updateSnapshot && run-s db:clean", "test:types": "run-s build:module && tsd --files test/*.test-d.ts", diff --git a/src/PostgrestBuilder.ts b/src/PostgrestBuilder.ts index ad3ca1ff..e48d69f0 100644 --- a/src/PostgrestBuilder.ts +++ b/src/PostgrestBuilder.ts @@ -13,7 +13,7 @@ export default abstract class PostgrestBuilder protected shouldThrowOnError = false protected signal?: AbortSignal protected fetch: Fetch - protected allowEmpty: boolean + protected isMaybeSingle: boolean constructor(builder: PostgrestBuilder) { this.method = builder.method @@ -23,7 +23,7 @@ export default abstract class PostgrestBuilder this.body = builder.body this.shouldThrowOnError = builder.shouldThrowOnError this.signal = builder.signal - this.allowEmpty = builder.allowEmpty + this.isMaybeSingle = builder.isMaybeSingle if (builder.fetch) { this.fetch = builder.fetch @@ -101,6 +101,28 @@ export default abstract class PostgrestBuilder if (countHeader && contentRange && contentRange.length > 1) { count = parseInt(contentRange[1]) } + + // Temporary partial fix for https://github.com/supabase/postgrest-js/issues/361 + // Issue persists e.g. for `.insert([...]).select().maybeSingle()` + if (this.isMaybeSingle && this.method === 'GET' && Array.isArray(data)) { + if (data.length > 1) { + error = { + // https://github.com/PostgREST/postgrest/blob/a867d79c42419af16c18c3fb019eba8df992626f/src/PostgREST/Error.hs#L553 + code: 'PGRST116', + details: `Results contain ${data.length} rows, application/vnd.pgrst.object+json requires 1 row`, + hint: null, + message: 'JSON object requested, multiple (or no) rows returned', + } + data = null + count = null + status = 406 + statusText = 'Not Acceptable' + } else if (data.length === 1) { + data = data[0] + } else { + data = null + } + } } else { const body = await res.text() @@ -126,7 +148,7 @@ export default abstract class PostgrestBuilder } } - if (error && this.allowEmpty && error?.details?.includes('Results contain 0 rows')) { + if (error && this.isMaybeSingle && error?.details?.includes('Results contain 0 rows')) { error = null status = 200 statusText = 'OK' diff --git a/src/PostgrestTransformBuilder.ts b/src/PostgrestTransformBuilder.ts index 646e85ab..9055d394 100644 --- a/src/PostgrestTransformBuilder.ts +++ b/src/PostgrestTransformBuilder.ts @@ -149,8 +149,14 @@ export default class PostgrestTransformBuilder< maybeSingle< ResultOne = Result extends (infer ResultOne)[] ? ResultOne : never >(): PostgrestBuilder { - this.headers['Accept'] = 'application/vnd.pgrst.object+json' - this.allowEmpty = true + // Temporary partial fix for https://github.com/supabase/postgrest-js/issues/361 + // Issue persists e.g. for `.insert([...]).select().maybeSingle()` + if (this.method === 'GET') { + this.headers['Accept'] = 'application/json' + } else { + this.headers['Accept'] = 'application/vnd.pgrst.object+json' + } + this.isMaybeSingle = true return this as PostgrestBuilder } diff --git a/test/transforms.ts b/test/transforms.ts index 7036a9a2..cce8e227 100644 --- a/test/transforms.ts +++ b/test/transforms.ts @@ -188,6 +188,28 @@ test('maybeSingle', async () => { `) }) +test('maybeSingle', async () => { + const res = await postgrest + .from('users') + .insert([{ username: 'a' }, { username: 'b' }]) + .select() + .maybeSingle() + expect(res).toMatchInlineSnapshot(` + Object { + "count": null, + "data": null, + "error": Object { + "code": "PGRST116", + "details": "Results contain 2 rows, application/vnd.pgrst.object+json requires 1 row", + "hint": null, + "message": "JSON object requested, multiple (or no) rows returned", + }, + "status": 406, + "statusText": "Not Acceptable", + } + `) +}) + test('select on insert', async () => { const res = await postgrest.from('users').insert({ username: 'foo' }).select('status') expect(res).toMatchInlineSnapshot(`