Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
434 changes: 434 additions & 0 deletions packages/core/postgrest-js/docs/SELECT_BUILDER_PLAN.md

Large diffs are not rendered by default.

33 changes: 30 additions & 3 deletions packages/core/postgrest-js/src/PostgrestQueryBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import PostgrestFilterBuilder from './PostgrestFilterBuilder'
import { GetResult } from './select-query-parser/result'
import { SelectItem, serializeSelectSpec } from './select-query-parser/select-builder'
import {
ClientServerOptions,
Fetch,
Expand Down Expand Up @@ -69,7 +70,9 @@ export default class PostgrestQueryBuilder<
/**
* Perform a SELECT query on the table or view.
*
* @param columns - The columns to retrieve, separated by commas. Columns can be renamed when returned with `customName:columnName`
* @param columns - The columns to retrieve. Can be:
* - A string with comma-separated column names (e.g., `'id, name, email'`)
* - An array of column names and/or field specs (e.g., `['id', { column: 'name', as: 'display_name' }]`)
*
* @param options - Named parameters
*
Expand All @@ -90,6 +93,19 @@ export default class PostgrestQueryBuilder<
* @remarks
* When using `count` with `.range()` or `.limit()`, the returned `count` is the total number of rows
* that match your filters, not the number of rows in the current page. Use this to build pagination UI.
*
* @example String-based select
* ```ts
* .select('id, name, email')
* .select('posts(id, title)')
* ```
*
* @example Array-based select (provides IDE autocomplete)
* ```ts
* .select(['id', 'name', 'email'])
* .select(['id', { relation: 'posts', select: ['id', 'title'] }])
* .select([{ column: 'username', as: 'display_name' }])
* ```
*/
select<
Query extends string = '*',
Expand All @@ -102,7 +118,7 @@ export default class PostgrestQueryBuilder<
ClientOptions
>,
>(
columns?: Query,
columns?: Query | SelectItem[],
options?: {
head?: boolean
count?: 'exact' | 'planned' | 'estimated'
Expand All @@ -119,9 +135,20 @@ export default class PostgrestQueryBuilder<
const { head = false, count } = options ?? {}

const method = head ? 'HEAD' : 'GET'

// Serialize array-based select specs to string
let columnsString: string
if (columns === undefined) {
columnsString = '*'
} else if (Array.isArray(columns)) {
columnsString = serializeSelectSpec(columns)
} else {
columnsString = columns
}

// Remove whitespaces except when quoted
let quoted = false
const cleanedColumns = (columns ?? '*')
const cleanedColumns = columnsString
.split('')
.map((c) => {
if (/\s/.test(c) && !quoted) {
Expand Down
30 changes: 27 additions & 3 deletions packages/core/postgrest-js/src/PostgrestTransformBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import PostgrestBuilder from './PostgrestBuilder'
import PostgrestFilterBuilder, { InvalidMethodError } from './PostgrestFilterBuilder'
import { GetResult } from './select-query-parser/result'
import { SelectItem, serializeSelectSpec } from './select-query-parser/select-builder'
import { CheckMatchingArrayTypes } from './types/types'
import { ClientServerOptions, GenericSchema } from './types/common/common'
import type { MaxAffectedEnabled } from './types/feature-flags'
Expand All @@ -21,13 +22,26 @@ export default class PostgrestTransformBuilder<
* return modified rows. By calling this method, modified rows are returned in
* `data`.
*
* @param columns - The columns to retrieve, separated by commas
* @param columns - The columns to retrieve. Can be:
* - A string with comma-separated column names (e.g., `'id, name, email'`)
* - An array of column names and/or field specs (e.g., `['id', { column: 'name', as: 'display_name' }]`)
*
* @example String-based select
* ```ts
* .select('id, name, email')
* ```
*
* @example Array-based select (provides IDE autocomplete)
* ```ts
* .select(['id', 'name', 'email'])
* .select([{ column: 'username', as: 'display_name' }])
* ```
*/
select<
Query extends string = '*',
NewResultOne = GetResult<Schema, Row, RelationName, Relationships, Query, ClientOptions>,
>(
columns?: Query
columns?: Query | SelectItem[]
): PostgrestFilterBuilder<
ClientOptions,
Schema,
Expand All @@ -41,9 +55,19 @@ export default class PostgrestTransformBuilder<
Relationships,
Method
> {
// Serialize array-based select specs to string
let columnsString: string
if (columns === undefined) {
columnsString = '*'
} else if (Array.isArray(columns)) {
columnsString = serializeSelectSpec(columns)
} else {
columnsString = columns
}

// Remove whitespaces except when quoted
let quoted = false
const cleanedColumns = (columns ?? '*')
const cleanedColumns = columnsString
.split('')
.map((c) => {
if (/\s/.test(c) && !quoted) {
Expand Down
11 changes: 11 additions & 0 deletions packages/core/postgrest-js/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,14 @@ export type { ClientServerOptions as PostgrestClientOptions } from './types/comm
// https://github.com/supabase/postgrest-js/issues/551
// To be replaced with a helper type that only uses public types
export type { GetResult as UnstableGetResult } from './select-query-parser/result'
// Array-based select builder types
export type {
SelectSpec,
SelectItem,
FieldSpec,
RelationSpec,
SpreadSpec,
CountSpec,
AggregateFunction,
} from './select-query-parser/select-builder'
export { serializeSelectSpec } from './select-query-parser/select-builder'
Loading
Loading