mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 18:05:11 +03:00
adds support for loading views and foreign tables
This commit is contained in:
1 parent
80ff7827dc
commit
fc7d2882d0
17 files changed
+407
-98
No files matched your search
@@ -1,4 +1,4 @@
|
||||
import { FC, useRef, useEffect, useState } from 'react'
|
||||
import { useRef, useEffect, useState } from 'react'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { useRouter } from 'next/router'
|
||||
import { find, isUndefined, noop } from 'lodash'
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
import { PropsWithChildren, useEffect } from 'react'
|
||||
import { isUndefined, noop } from 'lodash'
|
||||
import { PropsWithChildren, useEffect, useState } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { noop } from 'lodash'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
|
||||
import { checkPermissions, useParams, useStore } from 'hooks'
|
||||
import { Entity } from 'data/entity-types/entity-types-infinite-query'
|
||||
import { Entity } from 'data/entity-types/entity-type-query'
|
||||
import ProjectLayout from '../ProjectLayout/ProjectLayout'
|
||||
import TableEditorMenu from './TableEditorMenu'
|
||||
import NoPermission from 'components/ui/NoPermission'
|
||||
import useEntityType from 'hooks/misc/useEntityType'
|
||||
import Connecting from 'components/ui/Loading/Loading'
|
||||
import useTableRowsPrefetch from 'hooks/misc/useTableRowsPrefetch'
|
||||
import useLatest from 'hooks/misc/useLatest'
|
||||
|
||||
export interface TableEditorLayoutProps {
|
||||
selectedSchema?: string
|
||||
@@ -28,7 +33,9 @@ const TableEditorLayout = ({
|
||||
children,
|
||||
}: PropsWithChildren<TableEditorLayoutProps>) => {
|
||||
const { vault, meta, ui } = useStore()
|
||||
const { id, type } = useParams()
|
||||
const router = useRouter()
|
||||
const { id: _id } = useParams()
|
||||
const id = _id ? Number(_id) : undefined
|
||||
|
||||
const canReadTables = checkPermissions(PermissionAction.TENANT_SQL_ADMIN_READ, 'tables')
|
||||
|
||||
@@ -42,22 +49,70 @@ const TableEditorLayout = ({
|
||||
meta.policies.load()
|
||||
meta.publications.load()
|
||||
meta.extensions.load()
|
||||
|
||||
// [Joshen] pg-meta doesn't support loading views nor foreign tables by a specific ID yet
|
||||
// Separately, Alaister and I chatted that perhaps we leverage on pg-catalog's pg-class
|
||||
// table directly, so we can fetch the schema of tables/views/foreign-tables in one call
|
||||
// rather than trying to discern if the ID is a view, or foreign table (refer to below)
|
||||
meta.views.load()
|
||||
meta.foreignTables.load()
|
||||
}
|
||||
}, [ui.selectedProject?.ref])
|
||||
|
||||
const [loadedIds, setLoadedIds] = useState<Set<number>>(() => new Set())
|
||||
const isLoaded = id !== undefined && loadedIds.has(id)
|
||||
|
||||
const entity = useEntityType(id, function onNotFound(id) {
|
||||
setLoadedIds((loadedIds) => {
|
||||
const newLoadedIds = new Set(loadedIds)
|
||||
newLoadedIds.add(id)
|
||||
return newLoadedIds
|
||||
})
|
||||
})
|
||||
|
||||
const prefetch = useLatest(useTableRowsPrefetch())
|
||||
|
||||
useEffect(() => {
|
||||
if (ui.selectedProject?.ref && id) {
|
||||
meta.tables.loadById(Number(id))
|
||||
meta.views.loadById(Number(id))
|
||||
let mounted = true
|
||||
|
||||
function loadTable() {
|
||||
if (entity?.type) {
|
||||
switch (entity.type) {
|
||||
case 'materialized_view':
|
||||
case 'view':
|
||||
return meta.views.loadById(entity.id)
|
||||
|
||||
case 'foreign_table':
|
||||
return meta.foreignTables.loadById(entity.id)
|
||||
|
||||
default:
|
||||
return meta.tables.loadById(entity.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [ui.selectedProject?.ref, id])
|
||||
|
||||
loadTable()
|
||||
?.then(async (entity: any) => {
|
||||
await prefetch.current(entity)
|
||||
|
||||
return entity
|
||||
})
|
||||
.then((entity: any) => {
|
||||
if (mounted) {
|
||||
setLoadedIds((loadedIds) => {
|
||||
const newLoadedIds = new Set(loadedIds)
|
||||
newLoadedIds.add(entity.id ?? entity?.id)
|
||||
return newLoadedIds
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
if (mounted && entity?.id) {
|
||||
setLoadedIds((loadedIds) => {
|
||||
const newLoadedIds = new Set(loadedIds)
|
||||
newLoadedIds.add(entity.id)
|
||||
return newLoadedIds
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return () => {
|
||||
mounted = false
|
||||
}
|
||||
}, [entity])
|
||||
|
||||
useEffect(() => {
|
||||
if (isVaultEnabled) {
|
||||
@@ -75,7 +130,6 @@ const TableEditorLayout = ({
|
||||
|
||||
return (
|
||||
<ProjectLayout
|
||||
isLoading={isUndefined(selectedSchema)}
|
||||
product="Table editor"
|
||||
productMenu={
|
||||
<TableEditorMenu
|
||||
@@ -88,7 +142,7 @@ const TableEditorLayout = ({
|
||||
/>
|
||||
}
|
||||
>
|
||||
{children}
|
||||
{router.isReady && id !== undefined ? isLoaded ? children : <Connecting /> : children}
|
||||
</ProjectLayout>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -24,7 +24,8 @@ import type { PostgresSchema } from '@supabase/postgres-meta'
|
||||
|
||||
import { checkPermissions, useStore, useParams } from 'hooks'
|
||||
import ProductMenuItem from 'components/ui/ProductMenu/ProductMenuItem'
|
||||
import { Entity, useEntityTypesQuery } from 'data/entity-types/entity-types-infinite-query'
|
||||
import { useEntityTypesQuery } from 'data/entity-types/entity-types-infinite-query'
|
||||
import { Entity } from 'data/entity-types/entity-type-query'
|
||||
import { useProjectContext } from '../ProjectLayout/ProjectContext'
|
||||
import InfiniteList from 'components/ui/InfiniteList'
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { UseQueryOptions } from '@tanstack/react-query'
|
||||
import { useCallback } from 'react'
|
||||
import { ExecuteSqlData, useExecuteSqlPrefetch, useExecuteSqlQuery } from '../sql/execute-sql-query'
|
||||
|
||||
type getForeignKeyConstraintsVariables = {
|
||||
@@ -107,15 +108,17 @@ export const useForeignKeyConstraintsQuery = <
|
||||
)
|
||||
}
|
||||
|
||||
export const useForeignKeyConstraintsPrefetch = ({
|
||||
projectRef,
|
||||
connectionString,
|
||||
schema,
|
||||
}: ForeignKeyConstraintsVariables) => {
|
||||
return useExecuteSqlPrefetch({
|
||||
projectRef,
|
||||
connectionString,
|
||||
sql: getForeignKeyConstraintsQuery({ schema }),
|
||||
queryKey: ['foreign-key-constraints'],
|
||||
})
|
||||
export const useForeignKeyConstraintsPrefetch = () => {
|
||||
const prefetch = useExecuteSqlPrefetch()
|
||||
|
||||
return useCallback(
|
||||
({ projectRef, connectionString, schema }: ForeignKeyConstraintsVariables) =>
|
||||
prefetch({
|
||||
projectRef,
|
||||
connectionString,
|
||||
sql: getForeignKeyConstraintsQuery({ schema }),
|
||||
queryKey: ['foreign-key-constraints'],
|
||||
}),
|
||||
[prefetch]
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
import { UseQueryOptions } from '@tanstack/react-query'
|
||||
import { useCallback } from 'react'
|
||||
import { ExecuteSqlData, useExecuteSqlPrefetch, useExecuteSqlQuery } from '../sql/execute-sql-query'
|
||||
|
||||
type EntityTypeArgs = {
|
||||
id?: number
|
||||
}
|
||||
|
||||
export const entityTypeSqlQuery = ({ id }: EntityTypeArgs) => {
|
||||
const sql = /* SQL */ `
|
||||
select
|
||||
c.oid::int8 as "id",
|
||||
nc.nspname as "schema",
|
||||
c.relname as "name",
|
||||
case c.relkind
|
||||
when 'r' then 'table'
|
||||
when 'v' then 'view'
|
||||
when 'm' then 'materialized_view'
|
||||
when 'f' then 'foreign_table'
|
||||
when 'p' then 'partitioned_table'
|
||||
end as "type",
|
||||
obj_description(c.oid) as "comment",
|
||||
count(*) over() as "count"
|
||||
from
|
||||
pg_namespace nc
|
||||
join pg_class c on nc.oid = c.relnamespace
|
||||
where
|
||||
c.relkind in ('r', 'v', 'm', 'f', 'p')
|
||||
and not pg_is_other_temp_schema(nc.oid)
|
||||
and (
|
||||
pg_has_role(c.relowner, 'USAGE')
|
||||
or has_table_privilege(
|
||||
c.oid,
|
||||
'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER'
|
||||
)
|
||||
or has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES')
|
||||
)
|
||||
and c.oid = '${id}'
|
||||
limit 1;
|
||||
`
|
||||
|
||||
return sql
|
||||
}
|
||||
|
||||
export type Entity = {
|
||||
id: number
|
||||
schema: string
|
||||
name: string
|
||||
type: 'table' | 'view' | 'materialized_view' | 'foreign_table' | 'partitioned_table'
|
||||
comment: string | null
|
||||
}
|
||||
|
||||
export type EntityType = Entity | null
|
||||
|
||||
export type EntityTypeVariables = EntityTypeArgs & {
|
||||
projectRef?: string
|
||||
connectionString?: string
|
||||
}
|
||||
|
||||
export type EntityTypeData = EntityType
|
||||
export type EntityTypeError = unknown
|
||||
|
||||
export const useEntityTypeQuery = <TData extends EntityTypeData = EntityTypeData>(
|
||||
{ projectRef, connectionString, id, ...args }: EntityTypeVariables,
|
||||
{ enabled, ...options }: UseQueryOptions<ExecuteSqlData, EntityTypeError, TData> = {}
|
||||
) =>
|
||||
useExecuteSqlQuery(
|
||||
{
|
||||
projectRef,
|
||||
connectionString,
|
||||
sql: entityTypeSqlQuery({ id, ...args }),
|
||||
queryKey: ['entity-type', id],
|
||||
},
|
||||
{
|
||||
select(data) {
|
||||
return (data.result[0] ?? null) as TData
|
||||
},
|
||||
enabled:
|
||||
enabled && typeof projectRef !== 'undefined' && typeof id !== 'undefined' && !isNaN(id),
|
||||
...options,
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* useEntityTypePrefetch is used for prefetching table rows. For example, starting a query loading before a page is navigated to.
|
||||
*
|
||||
* @example
|
||||
* const prefetch = useEntityTypePrefetch()
|
||||
*
|
||||
* return (
|
||||
* <Link onMouseEnter={() => prefetch({ ...args })}>
|
||||
* Start loading on hover
|
||||
* </Link>
|
||||
* )
|
||||
*/
|
||||
export const useEntityTypePrefetch = () => {
|
||||
const prefetch = useExecuteSqlPrefetch()
|
||||
|
||||
return useCallback(
|
||||
({ projectRef, connectionString, id, ...args }: EntityTypeVariables) =>
|
||||
prefetch({
|
||||
projectRef,
|
||||
connectionString,
|
||||
sql: entityTypeSqlQuery({ id, ...args }),
|
||||
queryKey: ['entity-type', id],
|
||||
}),
|
||||
[prefetch]
|
||||
)
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useInfiniteQuery, UseInfiniteQueryOptions } from '@tanstack/react-query'
|
||||
import { executeSql, ExecuteSqlVariables } from 'data/sql/execute-sql-query'
|
||||
import { Entity } from './entity-type-query'
|
||||
import { entityTypeKeys } from './keys'
|
||||
|
||||
export type EntityTypesVariables = {
|
||||
@@ -9,14 +10,6 @@ export type EntityTypesVariables = {
|
||||
page?: number
|
||||
} & Pick<ExecuteSqlVariables, 'connectionString'>
|
||||
|
||||
export type Entity = {
|
||||
id: number
|
||||
schema: string
|
||||
name: string
|
||||
type: string
|
||||
comment: string | null
|
||||
}
|
||||
|
||||
export type EntityTypesResponse = {
|
||||
data: {
|
||||
entities: Entity[]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { UseQueryOptions } from '@tanstack/react-query'
|
||||
import { useCallback } from 'react'
|
||||
import { ExecuteSqlData, useExecuteSqlPrefetch, useExecuteSqlQuery } from '../sql/execute-sql-query'
|
||||
|
||||
export const getFDWsSql = () => {
|
||||
@@ -88,11 +89,17 @@ export const useFDWsQuery = <TData extends FDWsData = FDWsData>(
|
||||
options
|
||||
)
|
||||
|
||||
export const useFDWsPrefetch = ({ projectRef, connectionString }: FDWsVariables) => {
|
||||
return useExecuteSqlPrefetch({
|
||||
projectRef,
|
||||
connectionString,
|
||||
sql: getFDWsSql(),
|
||||
queryKey: ['fdws'],
|
||||
})
|
||||
export const useFDWsPrefetch = () => {
|
||||
const prefetch = useExecuteSqlPrefetch()
|
||||
|
||||
return useCallback(
|
||||
({ projectRef, connectionString }: FDWsVariables) =>
|
||||
prefetch({
|
||||
projectRef,
|
||||
connectionString,
|
||||
sql: getFDWsSql(),
|
||||
queryKey: ['fdws'],
|
||||
}),
|
||||
[prefetch]
|
||||
)
|
||||
}
|
||||
@@ -1,4 +1,10 @@
|
||||
import { QueryKey, useQuery, useQueryClient, UseQueryOptions } from '@tanstack/react-query'
|
||||
import {
|
||||
QueryClient,
|
||||
QueryKey,
|
||||
useQuery,
|
||||
useQueryClient,
|
||||
UseQueryOptions,
|
||||
} from '@tanstack/react-query'
|
||||
import md5 from 'blueimp-md5'
|
||||
import { post } from 'lib/common/fetch'
|
||||
import { API_URL } from 'lib/constants'
|
||||
@@ -55,19 +61,43 @@ export const useExecuteSqlQuery = <TData = ExecuteSqlData>(
|
||||
{ enabled: enabled && typeof projectRef !== 'undefined', ...options }
|
||||
)
|
||||
|
||||
export const useExecuteSqlPrefetch = ({
|
||||
projectRef,
|
||||
connectionString,
|
||||
sql,
|
||||
queryKey,
|
||||
}: ExecuteSqlVariables) => {
|
||||
export const prefetchExecuteSql = (
|
||||
client: QueryClient,
|
||||
{ projectRef, connectionString, sql, queryKey }: ExecuteSqlVariables
|
||||
) => {
|
||||
return client.prefetchQuery(sqlKeys.query(projectRef, queryKey ?? [md5(sql)]), ({ signal }) =>
|
||||
executeSql({ projectRef, connectionString, sql }, signal)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* useExecuteSqlPrefetch is used for prefetching a SQL query. For example, starting a query loading before a page is navigated to.
|
||||
*
|
||||
* @example
|
||||
* const prefetch = useExecuteSqlPrefetch()
|
||||
*
|
||||
* return (
|
||||
* <Link onMouseEnter={() => prefetch({ ...args })}>
|
||||
* Start loading on hover
|
||||
* </Link>
|
||||
* )
|
||||
*/
|
||||
export const useExecuteSqlPrefetch = () => {
|
||||
const client = useQueryClient()
|
||||
|
||||
return useCallback(() => {
|
||||
if (projectRef) {
|
||||
client.prefetchQuery(sqlKeys.query(projectRef, queryKey ?? [md5(sql)]), ({ signal }) =>
|
||||
executeSql({ projectRef, connectionString, sql }, signal)
|
||||
)
|
||||
}
|
||||
}, [projectRef])
|
||||
return useCallback(
|
||||
({ projectRef, connectionString, sql, queryKey }: ExecuteSqlVariables) => {
|
||||
if (projectRef) {
|
||||
return prefetchExecuteSql(client, {
|
||||
projectRef,
|
||||
connectionString,
|
||||
sql,
|
||||
queryKey,
|
||||
})
|
||||
}
|
||||
|
||||
return Promise.resolve()
|
||||
},
|
||||
[client]
|
||||
)
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { QueryKey, UseQueryOptions } from '@tanstack/react-query'
|
||||
import { Filter, Query, SupaTable } from 'components/grid'
|
||||
import { useCallback } from 'react'
|
||||
import { ExecuteSqlData, useExecuteSqlPrefetch, useExecuteSqlQuery } from '../sql/execute-sql-query'
|
||||
import { formatFilterValue } from './utils'
|
||||
|
||||
@@ -70,28 +71,28 @@ export const useTableRowsCountQuery = <TData extends TableRowsCountData = TableR
|
||||
* useTableRowsCountPrefetch is used for prefetching the table rows count. For example, starting a query loading before a page is navigated to.
|
||||
*
|
||||
* @example
|
||||
* const prefetch = useTableRowsCountPrefetch({ ...args })
|
||||
* const prefetch = useTableRowsCountPrefetch()
|
||||
*
|
||||
* return (
|
||||
* <Link onMouseEnter={() => prefetch()}>
|
||||
* <Link onMouseEnter={() => prefetch({ ...args })}>
|
||||
* Start loading on hover
|
||||
* </Link>
|
||||
* )
|
||||
*/
|
||||
export const useTableRowsCountPrefetch = ({
|
||||
projectRef,
|
||||
connectionString,
|
||||
queryKey,
|
||||
table,
|
||||
...args
|
||||
}: TableRowsCountVariables) => {
|
||||
return useExecuteSqlPrefetch({
|
||||
projectRef,
|
||||
connectionString,
|
||||
sql: getTableRowsCountSqlQuery({ table, ...args }),
|
||||
queryKey: [
|
||||
...(queryKey ?? []),
|
||||
{ table: { name: table?.name, schema: table?.schema }, ...args },
|
||||
],
|
||||
})
|
||||
export const useTableRowsCountPrefetch = () => {
|
||||
const prefetch = useExecuteSqlPrefetch()
|
||||
|
||||
return useCallback(
|
||||
({ projectRef, connectionString, queryKey, table, ...args }: TableRowsCountVariables) =>
|
||||
prefetch({
|
||||
projectRef,
|
||||
connectionString,
|
||||
sql: getTableRowsCountSqlQuery({ table, ...args }),
|
||||
queryKey: [
|
||||
...(queryKey ?? []),
|
||||
{ table: { name: table?.name, schema: table?.schema }, ...args },
|
||||
],
|
||||
}),
|
||||
[prefetch]
|
||||
)
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { QueryKey, UseQueryOptions } from '@tanstack/react-query'
|
||||
import { Filter, Query, Sort, SupaRow, SupaTable } from 'components/grid'
|
||||
import { useCallback } from 'react'
|
||||
import { ExecuteSqlData, useExecuteSqlPrefetch, useExecuteSqlQuery } from '../sql/execute-sql-query'
|
||||
import { getPagination } from '../utils/pagination'
|
||||
import { formatFilterValue } from './utils'
|
||||
@@ -109,20 +110,20 @@ export const useTableRowsQuery = <TData extends TableRowsData = TableRowsData>(
|
||||
* </Link>
|
||||
* )
|
||||
*/
|
||||
export const useTableRowsPrefetch = ({
|
||||
projectRef,
|
||||
connectionString,
|
||||
queryKey,
|
||||
table,
|
||||
...args
|
||||
}: TableRowsVariables) => {
|
||||
return useExecuteSqlPrefetch({
|
||||
projectRef,
|
||||
connectionString,
|
||||
sql: getTableRowsSqlQuery({ table, ...args }),
|
||||
queryKey: [
|
||||
...(queryKey ?? []),
|
||||
{ table: { name: table?.name, schema: table?.schema }, ...args },
|
||||
],
|
||||
})
|
||||
export const useTableRowsPrefetch = () => {
|
||||
const prefetch = useExecuteSqlPrefetch()
|
||||
|
||||
return useCallback(
|
||||
({ projectRef, connectionString, queryKey, table, ...args }: TableRowsVariables) =>
|
||||
prefetch({
|
||||
projectRef,
|
||||
connectionString,
|
||||
sql: getTableRowsSqlQuery({ table, ...args }),
|
||||
queryKey: [
|
||||
...(queryKey ?? []),
|
||||
{ table: { name: table?.name, schema: table?.schema }, ...args },
|
||||
],
|
||||
}),
|
||||
[prefetch]
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { Entity, useEntityTypeQuery } from 'data/entity-types/entity-type-query'
|
||||
import { entityTypeKeys } from 'data/entity-types/keys'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
/**
|
||||
* Tries to load an entity type from the cached list of entity types, or fetches it from the server.
|
||||
*/
|
||||
function useEntityType(id?: number, onNotFound?: (id: number) => void) {
|
||||
const queryClient = useQueryClient()
|
||||
const { project } = useProjectContext()
|
||||
|
||||
const existingEntity = useMemo(
|
||||
() =>
|
||||
(
|
||||
queryClient.getQueryCache().find(entityTypeKeys.list(project?.ref))?.state.data as any
|
||||
)?.pages
|
||||
?.flatMap((page: any) => page.data.entities)
|
||||
?.find((entity: any) => entity.id === id) as Entity | undefined,
|
||||
[project?.ref, id]
|
||||
)
|
||||
|
||||
const { data: entity } = useEntityTypeQuery(
|
||||
{
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
id,
|
||||
},
|
||||
{
|
||||
enabled: !existingEntity,
|
||||
onSettled(data) {
|
||||
if (!data && id !== undefined) {
|
||||
onNotFound?.(id)
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
return existingEntity ?? entity
|
||||
}
|
||||
|
||||
export default useEntityType
|
||||
@@ -0,0 +1,9 @@
|
||||
import { useRef } from 'react'
|
||||
|
||||
const useLatest = <T>(value: T): { readonly current: T } => {
|
||||
const ref = useRef(value)
|
||||
ref.current = value
|
||||
return ref
|
||||
}
|
||||
|
||||
export default useLatest
|
||||
@@ -0,0 +1,37 @@
|
||||
import { SupaTable } from 'components/grid'
|
||||
import { formatFilterURLParams, formatSortURLParams } from 'components/grid/SupabaseGrid.utils'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { useTableRowsPrefetch as _useTableRowsPrefetch } from 'data/table-rows/table-rows-query'
|
||||
import { useUrlState } from 'hooks'
|
||||
import { useCallback } from 'react'
|
||||
|
||||
/**
|
||||
* useTableRowsPrefetch is a wrapper around the base useTableRowsPrefetch that prefills the sort and filter params
|
||||
*/
|
||||
function useTableRowsPrefetch() {
|
||||
const [{ sort, filter }] = useUrlState({
|
||||
arrayKeys: ['sort', 'filter'],
|
||||
})
|
||||
const sorts = formatSortURLParams(sort as string[])
|
||||
const filters = formatFilterURLParams(filter as string[])
|
||||
|
||||
const { project } = useProjectContext()
|
||||
const prefetch = _useTableRowsPrefetch()
|
||||
|
||||
return useCallback(
|
||||
(table: SupaTable) =>
|
||||
prefetch({
|
||||
queryKey: [table.schema, table.name],
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
table,
|
||||
sorts,
|
||||
filters,
|
||||
page: 1,
|
||||
limit: 100,
|
||||
}),
|
||||
[project, sorts, filters]
|
||||
)
|
||||
}
|
||||
|
||||
export default useTableRowsPrefetch
|
||||
@@ -7,7 +7,7 @@ import { Alert, Button, Checkbox, IconExternalLink, Modal } from 'ui'
|
||||
import type { PostgresTable, PostgresColumn } from '@supabase/postgres-meta'
|
||||
|
||||
import { useStore, withAuth, useUrlState, useParams } from 'hooks'
|
||||
import { Entity } from 'data/entity-types/entity-types-infinite-query'
|
||||
import { Entity } from 'data/entity-types/entity-type-query'
|
||||
import { Dictionary } from 'components/grid'
|
||||
import { TableEditorLayout } from 'components/layouts'
|
||||
import { TableGridEditor } from 'components/interfaces'
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { PostgresTable } from '@supabase/postgres-meta'
|
||||
|
||||
import { NextPageWithLayout } from 'types'
|
||||
import { useStore, withAuth } from 'hooks'
|
||||
import { Entity } from 'data/entity-types/entity-types-infinite-query'
|
||||
import { Entity } from 'data/entity-types/entity-type-query'
|
||||
import { TableEditorLayout } from 'components/layouts'
|
||||
import { EmptyState, SidePanelEditor } from 'components/interfaces/TableGridEditor'
|
||||
import ConfirmationModal from 'components/ui/ConfirmationModal'
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
import type { PostgresTable } from '@supabase/postgres-meta'
|
||||
import PostgresMetaInterface from '../common/PostgresMetaInterface'
|
||||
import { get } from 'lib/common/fetch'
|
||||
import { ResponseError } from 'types'
|
||||
import PostgresMetaInterface, { IPostgresMetaInterface } from '../common/PostgresMetaInterface'
|
||||
import { IRootStore } from '../RootStore'
|
||||
|
||||
export interface IForeignTableStore extends IPostgresMetaInterface<Partial<PostgresTable>> {
|
||||
loadById: (id: number | string) => Promise<Partial<PostgresTable> | { error: ResponseError }>
|
||||
}
|
||||
|
||||
export default class ForeignTableStore extends PostgresMetaInterface<Partial<PostgresTable>> {
|
||||
constructor(
|
||||
rootStore: IRootStore,
|
||||
@@ -18,4 +24,19 @@ export default class ForeignTableStore extends PostgresMetaInterface<Partial<Pos
|
||||
async loadBySchema(schema: string) {
|
||||
return []
|
||||
}
|
||||
|
||||
async loadById(id: number | string) {
|
||||
try {
|
||||
const url = this.url.includes('?') ? `${this.url}&id=${id}` : `${this.url}?id=${id}`
|
||||
const response = await get(url, { headers: this.headers })
|
||||
if (response.error) throw response.error
|
||||
|
||||
const data = response as Partial<PostgresTable>
|
||||
// @ts-ignore
|
||||
this.data[id] = data
|
||||
return data
|
||||
} catch (error: any) {
|
||||
return { error }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,7 @@ import FunctionsStore from './FunctionsStore'
|
||||
import HooksStore from './HooksStore'
|
||||
import ExtensionsStore from './ExtensionsStore'
|
||||
import TypesStore from './TypesStore'
|
||||
import ForeignTableStore from './ForeignTableStore'
|
||||
import ForeignTableStore, { IForeignTableStore } from './ForeignTableStore'
|
||||
import ViewStore, { IViewStore } from './ViewStore'
|
||||
import { FOREIGN_KEY_DELETION_ACTION } from 'data/database/database-query-constants'
|
||||
|
||||
@@ -57,7 +57,7 @@ export interface IMetaStore {
|
||||
columns: IPostgresMetaInterface<PostgresColumn>
|
||||
schemas: IPostgresMetaInterface<PostgresSchema>
|
||||
views: IViewStore
|
||||
foreignTables: IPostgresMetaInterface<Partial<PostgresTable>>
|
||||
foreignTables: IForeignTableStore
|
||||
|
||||
hooks: IPostgresMetaInterface<any>
|
||||
roles: IRolesStore
|
||||
|
||||
Reference in new issue
Block a user