Add objectRecordCounts query to /metadata endpoint (#18054)
## Summary - Adds an `objectRecordCounts` query on the `/metadata` GraphQL endpoint that returns approximate record counts for all objects in the workspace - Uses PostgreSQL's `pg_class.reltuples` catalog stats — a single instant query instead of N `COUNT(*)` table scans - Replaces the previous `CombinedFindManyRecords` approach which hit the server's 20 root resolver limit and silently showed 0 for all counts on the settings Data Model page ### Server - `ObjectRecordCountDTO` — GraphQL type with `objectNamePlural` and `totalCount` - `ObjectRecordCountService` — reads `pg_class` catalog for the workspace schema - Query added to `ObjectMetadataResolver` with `@MetadataResolver()` + `NoPermissionGuard` ### Frontend - `OBJECT_RECORD_COUNTS` query added to `object-metadata/graphql/queries.ts` - `useCombinedGetTotalCount` simplified to a zero-argument hook using the new query - `SettingsObjectTable` simplified to a single hook call --------- Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+19
-40
@@ -1,48 +1,27 @@
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { EMPTY_QUERY } from '@/object-record/constants/EmptyQuery';
|
||||
import { type RecordGqlOperationSignature } from 'twenty-shared/types';
|
||||
import { useGenerateCombinedFindManyRecordsQuery } from '@/object-record/multiple-objects/hooks/useGenerateCombinedFindManyRecordsQuery';
|
||||
import { type CombinedFindManyRecordsQueryResult } from '@/object-record/multiple-objects/types/CombinedFindManyRecordsQueryResult';
|
||||
import { OBJECT_RECORD_COUNTS } from '@/object-metadata/graphql/queries';
|
||||
|
||||
export const useCombinedGetTotalCount = ({
|
||||
objectMetadataItems,
|
||||
skip = false,
|
||||
}: {
|
||||
objectMetadataItems: ObjectMetadataItem[];
|
||||
skip?: boolean;
|
||||
}) => {
|
||||
const operationSignatures = objectMetadataItems.map(
|
||||
(objectMetadataItem) =>
|
||||
({
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
variables: {},
|
||||
fields: {
|
||||
id: true,
|
||||
},
|
||||
}) satisfies RecordGqlOperationSignature,
|
||||
);
|
||||
type ObjectRecordCountsResult = {
|
||||
objectRecordCounts: {
|
||||
objectNamePlural: string;
|
||||
totalCount: number;
|
||||
}[];
|
||||
};
|
||||
|
||||
const apolloCoreClient = useApolloCoreClient();
|
||||
const findManyQuery = useGenerateCombinedFindManyRecordsQuery({
|
||||
operationSignatures,
|
||||
});
|
||||
export const useCombinedGetTotalCount = () => {
|
||||
const { data } = useQuery<ObjectRecordCountsResult>(OBJECT_RECORD_COUNTS);
|
||||
|
||||
const { data } = useQuery<CombinedFindManyRecordsQueryResult>(
|
||||
findManyQuery ?? EMPTY_QUERY,
|
||||
{
|
||||
skip,
|
||||
client: apolloCoreClient,
|
||||
},
|
||||
);
|
||||
|
||||
const totalCountByObjectMetadataItemNamePlural = Object.fromEntries(
|
||||
Object.entries(data ?? {}).map(([namePlural, objectRecordConnection]) => [
|
||||
namePlural,
|
||||
objectRecordConnection.totalCount,
|
||||
]),
|
||||
const totalCountByObjectMetadataItemNamePlural = useMemo(
|
||||
() =>
|
||||
Object.fromEntries(
|
||||
(data?.objectRecordCounts ?? []).map((item) => [
|
||||
item.objectNamePlural,
|
||||
item.totalCount,
|
||||
]),
|
||||
),
|
||||
[data],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user