(
[dataSourceName, 'capabilities'],
async () => {
const result =
diff --git a/frontend/libs/console/legacy-ce/src/lib/features/Data/hooks/useSetFunctionConfiguration.tsx b/frontend/libs/console/legacy-ce/src/lib/features/Data/hooks/useSetFunctionConfiguration.tsx
new file mode 100644
index 00000000000..3a13cef86fb
--- /dev/null
+++ b/frontend/libs/console/legacy-ce/src/lib/features/Data/hooks/useSetFunctionConfiguration.tsx
@@ -0,0 +1,87 @@
+import { useCallback } from 'react';
+import {
+ MetadataFunction,
+ QualifiedFunction,
+} from '../../hasura-metadata-types';
+import {
+ MetadataMigrationOptions,
+ useMetadataMigration,
+} from '../../MetadataAPI/hooks/useMetadataMigration';
+import {
+ MetadataSelectors,
+ areTablesEqual,
+ useInvalidateMetadata,
+ useMetadata,
+} from '../../hasura-metadata-api';
+import { transformErrorResponse } from '../errorUtils';
+
+export type MetadataFunctionPayload = {
+ function: QualifiedFunction;
+ configuration?: MetadataFunction['configuration'];
+ source: string;
+ comment?: string;
+};
+
+export const useSetFunctionConfiguration = ({
+ dataSourceName,
+ ...globalMutateOptions
+}: { dataSourceName: string } & MetadataMigrationOptions) => {
+ const invalidateMetadata = useInvalidateMetadata();
+
+ const { mutate, ...rest } = useMetadataMigration({
+ ...globalMutateOptions,
+ onSuccess: (data, variables, ctx) => {
+ invalidateMetadata();
+ globalMutateOptions?.onSuccess?.(data, variables, ctx);
+ },
+ errorTransform: transformErrorResponse,
+ });
+
+ const { data: { driver, resource_version, functions = [] } = {} } =
+ useMetadata(m => ({
+ driver: MetadataSelectors.findSource(dataSourceName)(m)?.kind,
+ resource_version: m.resource_version,
+ functions: MetadataSelectors.findSource(dataSourceName)(m)?.functions,
+ }));
+
+ const setFunctionConfiguration = useCallback(
+ ({
+ qualifiedFunction,
+ configuration,
+ ...mutationOptions
+ }: {
+ qualifiedFunction: QualifiedFunction;
+ configuration: MetadataFunction['configuration'];
+ } & MetadataMigrationOptions) => {
+ const metadataFunction = functions.find(fn =>
+ areTablesEqual(fn.function, qualifiedFunction)
+ );
+
+ const payload = {
+ type: `${driver}_set_function_customization`,
+ args: {
+ source: dataSourceName,
+ function: metadataFunction?.function,
+ configuration,
+ },
+ };
+
+ mutate(
+ {
+ query: {
+ type: 'bulk',
+ source: dataSourceName,
+ resource_version,
+ args: [payload],
+ },
+ },
+ {
+ ...mutationOptions,
+ }
+ );
+ },
+ [functions, driver, dataSourceName, mutate, resource_version]
+ );
+
+ return { setFunctionConfiguration, ...rest };
+};
diff --git a/frontend/libs/console/legacy-ce/src/lib/features/DataSource/common/capabilities.ts b/frontend/libs/console/legacy-ce/src/lib/features/DataSource/common/capabilities.ts
index fc2cf40cbd3..3db04fbe48b 100644
--- a/frontend/libs/console/legacy-ce/src/lib/features/DataSource/common/capabilities.ts
+++ b/frontend/libs/console/legacy-ce/src/lib/features/DataSource/common/capabilities.ts
@@ -1,13 +1,13 @@
-import { DriverCapability } from '../types';
+import { Capabilities } from '@hasura/dc-api-types';
-export const postgresCapabilities: DriverCapability = {
+export const postgresCapabilities: Capabilities = {
mutations: {
insert: {},
update: {},
delete: {},
},
queries: {},
- functions: {},
+ user_defined_functions: {},
data_schema: {
supports_foreign_keys: true,
},
diff --git a/frontend/libs/console/legacy-ce/src/lib/features/DataSource/common/defaultDatabaseProps.ts b/frontend/libs/console/legacy-ce/src/lib/features/DataSource/common/defaultDatabaseProps.ts
index db55430a701..2e535db03d3 100644
--- a/frontend/libs/console/legacy-ce/src/lib/features/DataSource/common/defaultDatabaseProps.ts
+++ b/frontend/libs/console/legacy-ce/src/lib/features/DataSource/common/defaultDatabaseProps.ts
@@ -16,6 +16,7 @@ export const defaultIntrospectionProps = {
getIsTableView: async () => Feature.NotImplemented,
getSupportedDataTypes: async () => Feature.NotImplemented,
getStoredProcedures: async () => Feature.NotImplemented,
+ getTrackableObjects: async () => Feature.NotImplemented,
};
export const defaultDatabaseProps: Database = {
diff --git a/frontend/libs/console/legacy-ce/src/lib/features/DataSource/gdc/index.ts b/frontend/libs/console/legacy-ce/src/lib/features/DataSource/gdc/index.ts
index a8b3a49d144..cd9050e4b5c 100644
--- a/frontend/libs/console/legacy-ce/src/lib/features/DataSource/gdc/index.ts
+++ b/frontend/libs/console/legacy-ce/src/lib/features/DataSource/gdc/index.ts
@@ -12,6 +12,7 @@ import {
getSupportedOperators,
getFKRelationships,
getDriverCapabilities,
+ getTrackableObjects,
} from './introspection';
import { getTableRows } from './query';
@@ -21,6 +22,7 @@ import { getTableRows } from './query';
* you'd have just the table name -> ["Album"] but in a db with schemas -> ["Public", "Album"].
*/
export type GDCTable = string[];
+export type GDCFunction = string[];
export const gdc: Database = {
...defaultDatabaseProps,
@@ -30,6 +32,7 @@ export const gdc: Database = {
getDatabaseConfiguration,
getDriverCapabilities,
getTrackableTables,
+ getTrackableObjects,
getDatabaseHierarchy: async () => Feature.NotImplemented,
getTableColumns,
getFKRelationships,
diff --git a/frontend/libs/console/legacy-ce/src/lib/features/DataSource/gdc/introspection/getTablesListAsTree.tsx b/frontend/libs/console/legacy-ce/src/lib/features/DataSource/gdc/introspection/getTablesListAsTree.tsx
index a8459e80b08..ceb649bd17e 100644
--- a/frontend/libs/console/legacy-ce/src/lib/features/DataSource/gdc/introspection/getTablesListAsTree.tsx
+++ b/frontend/libs/console/legacy-ce/src/lib/features/DataSource/gdc/introspection/getTablesListAsTree.tsx
@@ -5,6 +5,7 @@ import { GDCTable } from '..';
import { exportMetadata } from '../../api';
import { GetTablesListAsTreeProps } from '../../types';
import { convertToTreeData } from './utils';
+// import { QualifiedFunction } from '../../../hasura-metadata-types';
export const getTablesListAsTree = async ({
dataSourceName,
@@ -24,6 +25,11 @@ export const getTablesListAsTree = async ({
return table.table as GDCTable;
});
+ const functions = (source?.functions ?? []).map(f => {
+ if (typeof f.function === 'string') return [f.function] as GDCTable;
+ return f.function as GDCTable;
+ });
+
return {
title: (
@@ -37,6 +43,11 @@ export const getTablesListAsTree = async ({
),
key: JSON.stringify({ database: source.name }),
icon: ,
- children: tables.length ? convertToTreeData(tables, [], source.name) : [],
+ children: tables.length
+ ? [
+ ...convertToTreeData(tables, [], source.name),
+ ...convertToTreeData(functions, [], source.name, 'function'),
+ ]
+ : [],
};
};
diff --git a/frontend/libs/console/legacy-ce/src/lib/features/DataSource/gdc/introspection/getTrackableObjects.ts b/frontend/libs/console/legacy-ce/src/lib/features/DataSource/gdc/introspection/getTrackableObjects.ts
new file mode 100644
index 00000000000..110b493335d
--- /dev/null
+++ b/frontend/libs/console/legacy-ce/src/lib/features/DataSource/gdc/introspection/getTrackableObjects.ts
@@ -0,0 +1,79 @@
+import { Table } from '../../../hasura-metadata-types';
+import { runMetadataQuery } from '../../api';
+import { GetTrackableTablesProps, IntrospectedFunction } from '../../types';
+
+type TrackableObjects = {
+ functions: {
+ name: unknown;
+ volatility: 'STABLE' | 'VOLATILE';
+ }[];
+ tables: {
+ name: Table;
+ }[];
+};
+
+export type GetTrackableObjectsResponse = {
+ tables: {
+ name: string;
+ table: Table;
+ type: string;
+ }[];
+ functions: IntrospectedFunction[];
+};
+
+const adaptName = (name: unknown): string => {
+ if (typeof name === 'string') {
+ return name;
+ }
+ if (Array.isArray(name)) {
+ return name.join('.');
+ }
+
+ throw Error('getTrackableObjects: name is not string nor array:' + name);
+};
+
+export type GetTrackableObjectsProps = Pick<
+ GetTrackableTablesProps,
+ 'httpClient' | 'dataSourceName'
+>;
+
+export const getTrackableObjects = async ({
+ httpClient,
+ dataSourceName,
+}: GetTrackableObjectsProps) => {
+ try {
+ const result = await runMetadataQuery({
+ httpClient,
+ body: {
+ type: 'reference_get_source_trackables',
+ args: {
+ source: dataSourceName,
+ },
+ },
+ });
+
+ const tables = result.tables.map(({ name }) => {
+ /**
+ * Ideally each table is supposed to be GDCTable, but the server fix has not yet been merged to main.
+ * Right now it returns string as a table.
+ */
+ return {
+ name: adaptName(name),
+ table: name,
+ type: 'BASE TABLE',
+ };
+ });
+
+ const functions: IntrospectedFunction[] = result.functions.map(fn => {
+ return {
+ name: adaptName(fn.name),
+ qualifiedFunction: fn.name,
+ isVolatile: fn.volatility === 'VOLATILE',
+ };
+ });
+
+ return { tables, functions };
+ } catch (error) {
+ throw new Error('Error fetching GDC trackable objects');
+ }
+};
diff --git a/frontend/libs/console/legacy-ce/src/lib/features/DataSource/gdc/introspection/index.ts b/frontend/libs/console/legacy-ce/src/lib/features/DataSource/gdc/introspection/index.ts
index 0648ebdad24..cec03b61e51 100644
--- a/frontend/libs/console/legacy-ce/src/lib/features/DataSource/gdc/introspection/index.ts
+++ b/frontend/libs/console/legacy-ce/src/lib/features/DataSource/gdc/introspection/index.ts
@@ -5,5 +5,6 @@ export { getTableColumns } from './getTableColumns';
export { getFKRelationships } from './getFKRelationships';
export { getTablesListAsTree } from './getTablesListAsTree';
export { getTrackableTables } from './getTrackableTables';
+export { getTrackableObjects } from './getTrackableObjects';
export { convertToTreeData } from './utils';
export type { GetTableInfoResponse } from './types';
diff --git a/frontend/libs/console/legacy-ce/src/lib/features/DataSource/gdc/introspection/utils.tsx b/frontend/libs/console/legacy-ce/src/lib/features/DataSource/gdc/introspection/utils.tsx
index 0e23e1de672..3e201f4a040 100644
--- a/frontend/libs/console/legacy-ce/src/lib/features/DataSource/gdc/introspection/utils.tsx
+++ b/frontend/libs/console/legacy-ce/src/lib/features/DataSource/gdc/introspection/utils.tsx
@@ -3,22 +3,35 @@ import { DataNode } from 'antd/lib/tree';
import React from 'react';
import { FaTable, FaFolder } from 'react-icons/fa';
import { TableColumn } from '../../types';
+import { TbMathFunction } from 'react-icons/tb';
export function convertToTreeData(
tables: string[][],
key: string[],
- dataSourceName: string
+ dataSourceName: string,
+ mode?: 'function'
): DataNode[] {
if (tables.length === 0) return [];
if (tables[0].length === 1) {
const leafNodes: DataNode[] = tables.map(table => {
return {
- icon: ,
- key: JSON.stringify({
- database: dataSourceName,
- table: [...key, table[0]],
- }),
+ icon:
+ mode === 'function' ? (
+
+ ) : (
+
+ ),
+ key:
+ mode === 'function'
+ ? JSON.stringify({
+ database: dataSourceName,
+ function: [...key, table[0]],
+ })
+ : JSON.stringify({
+ database: dataSourceName,
+ table: [...key, table[0]],
+ }),
title: table[0],
};
});
diff --git a/frontend/libs/console/legacy-ce/src/lib/features/DataSource/index.ts b/frontend/libs/console/legacy-ce/src/lib/features/DataSource/index.ts
index 136ca420de7..83316607236 100644
--- a/frontend/libs/console/legacy-ce/src/lib/features/DataSource/index.ts
+++ b/frontend/libs/console/legacy-ce/src/lib/features/DataSource/index.ts
@@ -1,4 +1,4 @@
-import { OpenApiSchema } from '@hasura/dc-api-types';
+import { Capabilities, OpenApiSchema } from '@hasura/dc-api-types';
import { DataNode } from 'antd/lib/tree';
import { AxiosInstance } from 'axios';
import pickBy from 'lodash/pickBy';
@@ -35,7 +35,6 @@ import type {
TableRow,
Version,
WhereClause,
- DriverCapability,
StoredProcedure,
GetStoredProceduresProps,
} from './types';
@@ -57,6 +56,11 @@ import {
import { getAllSourceKinds } from './common/getAllSourceKinds';
import { getTableName } from './common/getTableName';
import { ReleaseType } from './types';
+import {
+ GetTrackableObjectsProps,
+ GetTrackableObjectsResponse,
+} from './gdc/introspection/getTrackableObjects';
+import { isObject } from '../../components/Common/utils/jsUtils';
export * from './common/utils';
export type { GDCTable } from './gdc';
@@ -121,7 +125,7 @@ export type Database = {
getDriverCapabilities: (
httpClient: AxiosInstance,
driver?: string
- ) => Promise;
+ ) => Promise;
getTrackableTables: (
props: GetTrackableTablesProps
) => Promise;
@@ -141,6 +145,9 @@ export type Database = {
getTrackableFunctions: (
props: GetTrackableFunctionProps
) => Promise;
+ getTrackableObjects: (
+ props: GetTrackableObjectsProps
+ ) => Promise;
getDatabaseSchemas: (
props: GetDatabaseSchemaProps
) => Promise;
@@ -547,13 +554,33 @@ export const DataSource = (httpClient: AxiosInstance) => ({
);
},
getTrackableFunctions: async (dataSourceName: string) => {
+ const functions: IntrospectedFunction[] = [];
const database = await getDatabaseMethods({ dataSourceName, httpClient });
- return (
- database.introspection?.getTrackableFunctions({
+
+ const trackableFunctions =
+ (await database.introspection?.getTrackableFunctions({
dataSourceName,
httpClient,
- }) ?? Feature.NotImplemented
- );
+ })) ?? [];
+
+ if (Array.isArray(trackableFunctions)) {
+ functions.push(...trackableFunctions);
+ }
+
+ const getTrackableObjectsFn = database.introspection?.getTrackableObjects;
+
+ if (getTrackableObjectsFn) {
+ const trackableObjects = await getTrackableObjectsFn({
+ dataSourceName,
+ httpClient,
+ });
+
+ if (isObject(trackableObjects) && 'functions' in trackableObjects) {
+ functions.push(...trackableObjects.functions);
+ }
+ }
+
+ return functions;
},
getDatabaseSchemas: async ({
dataSourceName,
diff --git a/frontend/libs/console/legacy-ce/src/lib/features/DataSource/types.ts b/frontend/libs/console/legacy-ce/src/lib/features/DataSource/types.ts
index 70574991f8d..2f0312e3b0a 100644
--- a/frontend/libs/console/legacy-ce/src/lib/features/DataSource/types.ts
+++ b/frontend/libs/console/legacy-ce/src/lib/features/DataSource/types.ts
@@ -1,4 +1,3 @@
-import { Capabilities } from '@hasura/dc-api-types';
import {
Legacy_SourceToRemoteSchemaRelationship,
LocalTableArrayRelationship,
@@ -195,10 +194,6 @@ export type GetIsTableViewProps = {
httpClient: NetworkArgs['httpClient'];
};
-export type DriverCapability = Capabilities & {
- functions?: Record;
-};
-
export type StoredProcedure = unknown;
export type GetStoredProceduresProps = {
dataSourceName: string;
diff --git a/frontend/libs/console/legacy-ce/src/lib/features/hasura-metadata-types/source/source.ts b/frontend/libs/console/legacy-ce/src/lib/features/hasura-metadata-types/source/source.ts
index 179a353fd90..6f66bbb5018 100644
--- a/frontend/libs/console/legacy-ce/src/lib/features/hasura-metadata-types/source/source.ts
+++ b/frontend/libs/console/legacy-ce/src/lib/features/hasura-metadata-types/source/source.ts
@@ -7,7 +7,7 @@ import {
} from './configuration';
import { LogicalModel } from './logicalModel';
import { NativeQuery } from './nativeQuery';
-import { MetadataTable } from './table';
+import { MetadataTable, Table } from './table';
import { StoredProcedure } from './storedProcedure';
export type NativeDrivers =
@@ -48,6 +48,10 @@ export type MetadataFunction = {
};
session_argument?: string;
exposed_as?: 'mutation' | 'query';
+ response?: {
+ type: 'table';
+ table: Table;
+ };
};
};
diff --git a/frontend/libs/console/legacy-ce/src/lib/utils/getDataRoute.ts b/frontend/libs/console/legacy-ce/src/lib/utils/getDataRoute.ts
index 276787c1ab7..82d5abd778d 100644
--- a/frontend/libs/console/legacy-ce/src/lib/utils/getDataRoute.ts
+++ b/frontend/libs/console/legacy-ce/src/lib/utils/getDataRoute.ts
@@ -1,4 +1,4 @@
-import { Table } from '../features/hasura-metadata-types';
+import { QualifiedFunction, Table } from '../features/hasura-metadata-types';
export const getRoute = () => ({
connectDatabase: (driver?: string) =>
@@ -21,4 +21,11 @@ export const getRoute = () => ({
)}`
);
},
+ function: (dataSourceName: string, fn: QualifiedFunction) => {
+ return encodeURI(
+ `/data/v2/manage/function?database=${dataSourceName}&function=${JSON.stringify(
+ fn
+ )}`
+ );
+ },
});
diff --git a/frontend/package.json b/frontend/package.json
index 9780159287b..651d3344e4a 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -36,7 +36,7 @@
"@babel/plugin-transform-runtime": "^7.14.5",
"@graphql-codegen/core": "^1.17.8",
"@graphql-codegen/typescript": "^1.17.10",
- "@hasura/dc-api-types": "^0.30.0",
+ "@hasura/dc-api-types": "^0.32.0",
"@hookform/resolvers": "2.8.10",
"@radix-ui/colors": "^0.1.8",
"@radix-ui/react-alert-dialog": "^1.0.3",
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index c1d89235475..3b9a325f42c 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -3375,10 +3375,10 @@ __metadata:
languageName: node
linkType: hard
-"@hasura/dc-api-types@npm:^0.30.0":
- version: 0.30.0
- resolution: "@hasura/dc-api-types@npm:0.30.0"
- checksum: fbf0376dae3252cac85dd343d77faaf82d7e9100ce5c3a18822e87e7d35550bca0c110f901da766e4099698228eb3b7e25d10f4b305b454e1f64d9ad4c87ae2b
+"@hasura/dc-api-types@npm:^0.32.0":
+ version: 0.32.0
+ resolution: "@hasura/dc-api-types@npm:0.32.0"
+ checksum: c95adc03c894cf737a0e1d366e5726f17156f13ec5d30be205dc705e2e0b55a0796d33603d8eee89926b1153503c171b461c4bace8475598bae7db33f94e0910
languageName: node
linkType: hard
@@ -18392,7 +18392,7 @@ __metadata:
"@graphql-codegen/core": ^1.17.8
"@graphql-codegen/typescript": ^1.17.10
"@graphql-codegen/typescript-operations": ^2.5.5
- "@hasura/dc-api-types": ^0.30.0
+ "@hasura/dc-api-types": ^0.32.0
"@hookform/devtools": 4.0.1
"@hookform/resolvers": 2.8.10
"@nrwl/cli": 15.8.1