diff --git a/packages/core/postgrest-js/src/PostgrestFilterBuilder.ts b/packages/core/postgrest-js/src/PostgrestFilterBuilder.ts index cb53017f4c..0a5cd5ba2b 100644 --- a/packages/core/postgrest-js/src/PostgrestFilterBuilder.ts +++ b/packages/core/postgrest-js/src/PostgrestFilterBuilder.ts @@ -74,6 +74,11 @@ type ResolveFilterRelationshipValue< : unknown : never +export type ResolveContainsFilterValue = + NonNullable extends readonly (infer Element)[] + ? readonly Element[] + : string | readonly unknown[] | Record + export type InvalidMethodError = { Error: S } type NonNullableColumn, Col extends string> = Col extends keyof T @@ -1004,12 +1009,12 @@ export default class PostgrestFilterBuilder< * } * ``` */ - contains( + contains( column: ColumnName, - value: string | ReadonlyArray | Record - ): this - contains(column: string, value: string | readonly unknown[] | Record): this - contains(column: string, value: string | readonly unknown[] | Record): this { + value: ColumnName extends keyof Row + ? ResolveContainsFilterValue + : string | readonly unknown[] | Record + ): this { if (typeof value === 'string') { // range types can be inclusive '[', ']' or exclusive '(', ')' so just // keep it simple and accept a string @@ -1154,12 +1159,12 @@ export default class PostgrestFilterBuilder< * * ``` */ - containedBy( + containedBy( column: ColumnName, - value: string | ReadonlyArray | Record - ): this - containedBy(column: string, value: string | readonly unknown[] | Record): this - containedBy(column: string, value: string | readonly unknown[] | Record): this { + value: ColumnName extends keyof Row + ? ResolveContainsFilterValue + : string | readonly unknown[] | Record + ): this { if (typeof value === 'string') { // range this.url.searchParams.append(column, `cd.${value}`) diff --git a/packages/core/postgrest-js/test/index.test-d.ts b/packages/core/postgrest-js/test/index.test-d.ts index 8cf886e28c..39ae1f1991 100644 --- a/packages/core/postgrest-js/test/index.test-d.ts +++ b/packages/core/postgrest-js/test/index.test-d.ts @@ -563,3 +563,37 @@ type WithThrowOnError = expectType>(true) } } + +// .contains() and .containedBy() value typing (Issue #435) +{ + // Array columns require an array of the element type + postgrest.from('cornercase').select().contains('array_column', ['test']) + postgrest + .from('cornercase') + .select() + .contains('array_column', ['test'] as const) + postgrest.from('cornercase').select().containedBy('array_column', ['test']) + postgrest + .from('cornercase') + .select() + .containedBy('array_column', ['test'] as const) + + // @ts-expect-error Argument of type 'string' is not assignable to parameter of type 'readonly string[]' + postgrest.from('cornercase').select().contains('array_column', 'test') + // @ts-expect-error Argument of type 'string' is not assignable to parameter of type 'readonly string[]' + postgrest.from('cornercase').select().containedBy('array_column', 'test') + // @ts-expect-error Type 'number' is not assignable to type 'string' + postgrest.from('cornercase').select().contains('array_column', [123]) + // @ts-expect-error Type 'number' is not assignable to type 'string' + postgrest.from('cornercase').select().containedBy('array_column', [123]) + // @ts-expect-error Object literal may only specify known properties, and 'foo' does not exist in type 'readonly string[]' + postgrest.from('cornercase').select().contains('array_column', { foo: 'bar' }) + // @ts-expect-error Object literal may only specify known properties, and 'foo' does not exist in type 'readonly string[]' + postgrest.from('cornercase').select().containedBy('array_column', { foo: 'bar' }) + + // Range and JSON columns accept string and objects + postgrest.from('users').select().contains('age_range', '[1,2)') + postgrest.from('users').select().containedBy('age_range', '[1,2)') + postgrest.from('users').select().contains('data', { foo: 'bar' }) + postgrest.from('users').select().containedBy('data', { foo: 'bar' }) +}