mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
fix: Fix the sort feature in the Table editor (#26865)
* Expand the Sort type with a table property. * Add a qualifier for the sort when sending a fetch table query. * Fix the tests.
This commit is contained in:
1 parent
3deeeb4988
commit
e1cf9d61ae
8 files changed
+36
-39
No files matched your search
@@ -133,7 +133,7 @@ const SupabaseGridLayout = (props: SupabaseGridProps) => {
|
||||
const [{ sort, filter }, setParams] = useUrlState({
|
||||
arrayKeys: ['sort', 'filter'],
|
||||
})
|
||||
const sorts = formatSortURLParams(sort as string[])
|
||||
const sorts = formatSortURLParams(props.table.name, sort as string[] | undefined)
|
||||
const filters = formatFilterURLParams(filter as string[])
|
||||
|
||||
const roleImpersonationState = useRoleImpersonationStateSnapshot()
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import AwesomeDebouncePromise from 'awesome-debounce-promise'
|
||||
import type { Filter } from 'components/grid/types'
|
||||
import { compact } from 'lodash'
|
||||
import type { Dictionary } from 'types'
|
||||
import { FilterOperatorOptions } from './components/header/filter'
|
||||
import { STORAGE_KEY_PREFIX } from './constants'
|
||||
import { InitialStateType } from './store/reducers'
|
||||
import type { Sort, SupabaseGridProps, SupaColumn, SupaTable } from './types'
|
||||
import type { Dictionary } from 'types'
|
||||
import { FilterOperatorOptions } from './components/header/filter'
|
||||
import type { Filter } from 'components/grid/types'
|
||||
|
||||
/**
|
||||
* Ensure that if editable is false, we should remove all editing actions
|
||||
@@ -26,19 +27,18 @@ export function cleanupProps(props: SupabaseGridProps) {
|
||||
}
|
||||
}
|
||||
|
||||
export function formatSortURLParams(sort?: string[]) {
|
||||
return (
|
||||
Array.isArray(sort)
|
||||
? sort
|
||||
.map((s) => {
|
||||
const [column, order] = s.split(':')
|
||||
// Reject any possible malformed sort param
|
||||
if (!column || !order) return undefined
|
||||
else return { column, ascending: order === 'asc' }
|
||||
})
|
||||
.filter((s) => s !== undefined)
|
||||
: []
|
||||
) as Sort[]
|
||||
export function formatSortURLParams(tableName: string, sort?: string[]): Sort[] {
|
||||
if (Array.isArray(sort)) {
|
||||
return compact(
|
||||
sort.map((s) => {
|
||||
const [column, order] = s.split(':')
|
||||
// Reject any possible malformed sort param
|
||||
if (!column || !order) return undefined
|
||||
else return { table: tableName, column, ascending: order === 'asc' }
|
||||
})
|
||||
)
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
export function formatFilterURLParams(filter?: string[]): Filter[] {
|
||||
|
||||
@@ -66,8 +66,8 @@ export interface SortOverlayProps {
|
||||
|
||||
const SortOverlay = ({ table, sorts: sortsFromUrl, onApplySorts }: SortOverlayProps) => {
|
||||
const initialSorts = useMemo(
|
||||
() => formatSortURLParams((sortsFromUrl as string[]) ?? []),
|
||||
[sortsFromUrl]
|
||||
() => formatSortURLParams(table.name, sortsFromUrl ?? []),
|
||||
[table.name, sortsFromUrl]
|
||||
)
|
||||
const [sorts, setSorts] = useState<Sort[]>(initialSorts)
|
||||
|
||||
@@ -82,7 +82,7 @@ const SortOverlay = ({ table, sorts: sortsFromUrl, onApplySorts }: SortOverlayPr
|
||||
}) || []
|
||||
|
||||
function onAddSort(columnName: string | number) {
|
||||
setSorts([...sorts, { column: columnName as string, ascending: true }])
|
||||
setSorts([...sorts, { table: table.name, column: columnName as string, ascending: true }])
|
||||
}
|
||||
|
||||
const onDeleteSort = useCallback((column: string) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ident, literal, format } from '@scaleleap/pg-format'
|
||||
import type { Filter, QueryPagination, QueryTable, Sort } from '../types'
|
||||
import { format, ident, literal } from '@scaleleap/pg-format'
|
||||
import type { Dictionary } from 'types'
|
||||
import type { Filter, QueryPagination, QueryTable, Sort } from '../types'
|
||||
|
||||
export function countQuery(
|
||||
table: QueryTable,
|
||||
@@ -223,7 +223,7 @@ function applySorts(query: string, sorts: Sort[]) {
|
||||
.map((x) => {
|
||||
const order = x.ascending ? 'asc' : 'desc'
|
||||
const nullOrder = x.nullsFirst ? 'nulls first' : 'nulls last'
|
||||
return `${ident(x.column)} ${order} ${nullOrder}`
|
||||
return `${ident(x.table)}.${ident(x.column)} ${order} ${nullOrder}`
|
||||
})
|
||||
.join(', ')}`
|
||||
return query
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { Filter, FilterOperator, QueryTable, Sort } from '../types'
|
||||
import type { Dictionary } from 'types'
|
||||
import type { Filter, FilterOperator, QueryTable, Sort } from '../types'
|
||||
import { IQueryModifier, QueryModifier } from './QueryModifier'
|
||||
|
||||
export interface IQueryFilter {
|
||||
filter: (column: string, operator: FilterOperator, value: string) => IQueryFilter
|
||||
match: (criteria: Dictionary<any>) => IQueryFilter
|
||||
order: (column: string, ascending?: boolean, nullsFirst?: boolean) => IQueryFilter
|
||||
order: (table: string, column: string, ascending?: boolean, nullsFirst?: boolean) => IQueryFilter
|
||||
}
|
||||
|
||||
export class QueryFilter implements IQueryFilter, IQueryModifier {
|
||||
@@ -31,8 +31,9 @@ export class QueryFilter implements IQueryFilter, IQueryModifier {
|
||||
return this
|
||||
}
|
||||
|
||||
order(column: string, ascending = true, nullsFirst = false) {
|
||||
order(table: string, column: string, ascending = true, nullsFirst = false) {
|
||||
this.sorts.push({
|
||||
table: table,
|
||||
column: column,
|
||||
ascending,
|
||||
nullsFirst,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { CalculatedColumn, RenderHeaderCellProps } from 'react-data-grid'
|
||||
|
||||
export interface Sort {
|
||||
table: string
|
||||
column: string
|
||||
ascending?: boolean
|
||||
nullsFirst?: boolean
|
||||
|
||||
@@ -60,7 +60,7 @@ export const fetchAllTableRows = async ({
|
||||
queryChains = queryChains.filter(filter.column, filter.operator, value)
|
||||
})
|
||||
sorts.forEach((sort) => {
|
||||
queryChains = queryChains.order(sort.column, sort.ascending, sort.nullsFirst)
|
||||
queryChains = queryChains.order(sort.table, sort.column, sort.ascending, sort.nullsFirst)
|
||||
})
|
||||
|
||||
// Starting from page 0, fetch 500 records per call
|
||||
@@ -134,7 +134,7 @@ export const getTableRowsSqlQuery = ({
|
||||
queryChains = queryChains.filter(x.column, x.operator, value)
|
||||
})
|
||||
sorts.forEach((x) => {
|
||||
queryChains = queryChains.order(x.column, x.ascending, x.nullsFirst)
|
||||
queryChains = queryChains.order(x.table, x.column, x.ascending, x.nullsFirst)
|
||||
})
|
||||
|
||||
// getPagination is expecting to start from 0
|
||||
|
||||
@@ -1,26 +1,21 @@
|
||||
import { formatSortURLParams, formatFilterURLParams } from 'components/grid/SupabaseGrid.utils'
|
||||
import { formatFilterURLParams, formatSortURLParams } from 'components/grid/SupabaseGrid.utils'
|
||||
|
||||
// Sort URL syntax: `column:order`
|
||||
describe('SupabaseGrid.utils: formatSortURLParams', () => {
|
||||
test('should return an array of sort options based on URL params', () => {
|
||||
const mockInput = ['id:asc', 'name:desc']
|
||||
const output = formatSortURLParams(mockInput)
|
||||
const output = formatSortURLParams('fakeTable', mockInput)
|
||||
expect(output).toStrictEqual([
|
||||
{
|
||||
column: 'id',
|
||||
ascending: true,
|
||||
},
|
||||
{
|
||||
column: 'name',
|
||||
ascending: false,
|
||||
},
|
||||
{ table: 'fakeTable', column: 'id', ascending: true },
|
||||
{ table: 'fakeTable', column: 'name', ascending: false },
|
||||
])
|
||||
})
|
||||
test('should reject any malformed sort options based on URL params', () => {
|
||||
const mockInput = ['id', 'name:asc', ':asc']
|
||||
const output = formatSortURLParams(mockInput)
|
||||
const output = formatSortURLParams('fakeTable', mockInput)
|
||||
expect(output).toStrictEqual([
|
||||
{
|
||||
table: 'fakeTable',
|
||||
column: 'name',
|
||||
ascending: true,
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user