data source query requests

This commit is contained in:
Nate Kelley 2025-03-24 15:48:29 -06:00
parent 87262ad102
commit 3618bd45a4
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
10 changed files with 529 additions and 104 deletions

View File

@ -9,6 +9,7 @@ export enum DataSourceStatus {
export enum DataSourceTypes {
postgres = 'postgres',
supabase = 'supabase',
mysql = 'mysql',
bigquery = 'bigquery',
snowflake = 'snowflake',
@ -16,7 +17,6 @@ export enum DataSourceTypes {
mariadb = 'mariadb',
sqlserver = 'sqlserver',
databricks = 'databricks',
supabase = 'supabase',
athena = 'athena',
other = 'other'
}

View File

@ -0,0 +1,373 @@
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import {
listDatasources,
getDatasource,
deleteDatasource,
createBigQueryDataSource,
createDatabricksDataSource,
createMySQLDataSource,
createPostgresDataSource,
createRedshiftDataSource,
createSnowflakeDataSource,
createSQLServerDataSource,
updatePostgresDataSource,
updateMySQLDataSource,
updateBigQueryDataSource,
updateRedshiftDataSource,
updateSnowflakeDataSource,
updateDatabricksDataSource,
updateSQLServerDataSource
} from './requests';
import { queryKeys } from '@/api/query_keys';
import { useBusterNotifications } from '@/context/BusterNotifications';
import { DataSourceTypes } from '@/api/asset_interfaces/datasources/interfaces';
export const useListDatasources = (enabled: boolean = true) => {
return useQuery({
...queryKeys.datasourceGetList,
queryFn: listDatasources,
enabled
});
};
export const useGetDatasource = (id: string | undefined) => {
return useQuery({
...queryKeys.datasourceGet(id!),
queryFn: () => getDatasource(id!),
enabled: !!id
});
};
export const useDeleteDatasource = () => {
const queryClient = useQueryClient();
const { openConfirmModal } = useBusterNotifications();
const mutationFn = async (dataSourceId: string) => {
return openConfirmModal({
title: 'Delete Data Source',
content: 'Are you sure you want to delete this data source?',
onOk: async () => deleteDatasource(dataSourceId)
});
};
return useMutation({
mutationFn,
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: queryKeys.datasourceGetList.queryKey
});
}
});
};
export const useCreatePostgresDataSource = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: createPostgresDataSource,
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: queryKeys.datasourceGetList.queryKey
});
}
});
};
export const useUpdatePostgresDataSource = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: updatePostgresDataSource,
onSuccess: (_, variables) => {
queryClient.invalidateQueries({
queryKey: queryKeys.datasourceGetList.queryKey
});
queryClient.invalidateQueries({
queryKey: queryKeys.datasourceGet(variables.id).queryKey
});
}
});
};
export const useCreateMySQLDataSource = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: createMySQLDataSource,
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: queryKeys.datasourceGetList.queryKey
});
}
});
};
export const useUpdateMySQLDataSource = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: updateMySQLDataSource,
onSuccess: (_, variables) => {
queryClient.invalidateQueries({
queryKey: queryKeys.datasourceGetList.queryKey
});
queryClient.invalidateQueries({
queryKey: queryKeys.datasourceGet(variables.id).queryKey
});
}
});
};
export const useCreateBigQueryDataSource = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: createBigQueryDataSource,
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: queryKeys.datasourceGetList.queryKey
});
}
});
};
export const useUpdateBigQueryDataSource = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: updateBigQueryDataSource,
onSuccess: (_, variables) => {
queryClient.invalidateQueries({
queryKey: queryKeys.datasourceGetList.queryKey
});
queryClient.invalidateQueries({
queryKey: queryKeys.datasourceGet(variables.id).queryKey
});
}
});
};
export const useCreateRedshiftDataSource = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: createRedshiftDataSource,
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: queryKeys.datasourceGetList.queryKey
});
}
});
};
export const useUpdateRedshiftDataSource = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: updateRedshiftDataSource,
onSuccess: (_, variables) => {
queryClient.invalidateQueries({
queryKey: queryKeys.datasourceGetList.queryKey
});
queryClient.invalidateQueries({
queryKey: queryKeys.datasourceGet(variables.id).queryKey
});
}
});
};
export const useCreateSnowflakeDataSource = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: createSnowflakeDataSource,
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: queryKeys.datasourceGetList.queryKey
});
}
});
};
export const useUpdateSnowflakeDataSource = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: updateSnowflakeDataSource,
onSuccess: (_, variables) => {
queryClient.invalidateQueries({
queryKey: queryKeys.datasourceGetList.queryKey
});
queryClient.invalidateQueries({
queryKey: queryKeys.datasourceGet(variables.id).queryKey
});
}
});
};
export const useCreateDatabricksDataSource = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: createDatabricksDataSource,
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: queryKeys.datasourceGetList.queryKey
});
}
});
};
export const useUpdateDatabricksDataSource = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: updateDatabricksDataSource,
onSuccess: (_, variables) => {
queryClient.invalidateQueries({
queryKey: queryKeys.datasourceGetList.queryKey
});
queryClient.invalidateQueries({
queryKey: queryKeys.datasourceGet(variables.id).queryKey
});
}
});
};
export const useCreateSQLServerDataSource = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: createSQLServerDataSource,
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: queryKeys.datasourceGetList.queryKey
});
}
});
};
export const useUpdateSQLServerDataSource = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: updateSQLServerDataSource,
onSuccess: (_, variables) => {
queryClient.invalidateQueries({
queryKey: queryKeys.datasourceGetList.queryKey
});
queryClient.invalidateQueries({
queryKey: queryKeys.datasourceGet(variables.id).queryKey
});
}
});
};
// Type definitions for the create datasource parameters
type PostgresCreateParams = Parameters<typeof createPostgresDataSource>[0];
type MySQLCreateParams = Parameters<typeof createMySQLDataSource>[0];
type BigQueryCreateParams = Parameters<typeof createBigQueryDataSource>[0];
type RedshiftCreateParams = Parameters<typeof createRedshiftDataSource>[0];
type SnowflakeCreateParams = Parameters<typeof createSnowflakeDataSource>[0];
type DatabricksCreateParams = Parameters<typeof createDatabricksDataSource>[0];
type SQLServerCreateParams = Parameters<typeof createSQLServerDataSource>[0];
// Type definitions for the update datasource parameters
type PostgresUpdateParams = Parameters<typeof updatePostgresDataSource>[0];
type MySQLUpdateParams = Parameters<typeof updateMySQLDataSource>[0];
type BigQueryUpdateParams = Parameters<typeof updateBigQueryDataSource>[0];
type RedshiftUpdateParams = Parameters<typeof updateRedshiftDataSource>[0];
type SnowflakeUpdateParams = Parameters<typeof updateSnowflakeDataSource>[0];
type DatabricksUpdateParams = Parameters<typeof updateDatabricksDataSource>[0];
type SQLServerUpdateParams = Parameters<typeof updateSQLServerDataSource>[0];
// Union type for create datasource parameters
type CreateDatasourceParams =
| PostgresCreateParams
| MySQLCreateParams
| BigQueryCreateParams
| RedshiftCreateParams
| SnowflakeCreateParams
| DatabricksCreateParams
| SQLServerCreateParams;
// Union type for update datasource parameters
type UpdateDatasourceParams =
| PostgresUpdateParams
| MySQLUpdateParams
| BigQueryUpdateParams
| RedshiftUpdateParams
| SnowflakeUpdateParams
| DatabricksUpdateParams
| SQLServerUpdateParams;
export const useCreateDatasource = () => {
const createPostgres = useCreatePostgresDataSource();
const createMySQL = useCreateMySQLDataSource();
const createBigQuery = useCreateBigQueryDataSource();
const createRedshift = useCreateRedshiftDataSource();
const createSnowflake = useCreateSnowflakeDataSource();
const createDatabricks = useCreateDatabricksDataSource();
const createSQLServer = useCreateSQLServerDataSource();
return {
mutateAsync: async (credentials: CreateDatasourceParams) => {
switch (credentials.type) {
case DataSourceTypes.postgres:
return createPostgres.mutateAsync(credentials as PostgresCreateParams);
case DataSourceTypes.mysql:
case DataSourceTypes.mariadb:
return createMySQL.mutateAsync(credentials as MySQLCreateParams);
case DataSourceTypes.bigquery:
return createBigQuery.mutateAsync(credentials as BigQueryCreateParams);
case DataSourceTypes.redshift:
return createRedshift.mutateAsync(credentials as RedshiftCreateParams);
case DataSourceTypes.snowflake:
return createSnowflake.mutateAsync(credentials as SnowflakeCreateParams);
case DataSourceTypes.databricks:
return createDatabricks.mutateAsync(credentials as DatabricksCreateParams);
case DataSourceTypes.sqlserver:
return createSQLServer.mutateAsync(credentials as SQLServerCreateParams);
default:
throw new Error(`Unsupported data source type: ${credentials.type}`);
}
},
isLoading:
createPostgres.isPending ||
createMySQL.isPending ||
createBigQuery.isPending ||
createRedshift.isPending ||
createSnowflake.isPending ||
createDatabricks.isPending ||
createSQLServer.isPending
};
};
export const useUpdateDatasource = () => {
const updatePostgres = useUpdatePostgresDataSource();
const updateMySQL = useUpdateMySQLDataSource();
const updateBigQuery = useUpdateBigQueryDataSource();
const updateRedshift = useUpdateRedshiftDataSource();
const updateSnowflake = useUpdateSnowflakeDataSource();
const updateDatabricks = useUpdateDatabricksDataSource();
const updateSQLServer = useUpdateSQLServerDataSource();
return {
mutateAsync: async (credentials: UpdateDatasourceParams) => {
switch (credentials.type as string) {
case DataSourceTypes.postgres:
case DataSourceTypes.supabase:
return updatePostgres.mutateAsync(credentials as PostgresUpdateParams);
case DataSourceTypes.mysql:
case DataSourceTypes.mariadb:
return updateMySQL.mutateAsync(credentials as MySQLUpdateParams);
case DataSourceTypes.bigquery:
return updateBigQuery.mutateAsync(credentials as BigQueryUpdateParams);
case DataSourceTypes.redshift:
return updateRedshift.mutateAsync(credentials as RedshiftUpdateParams);
case DataSourceTypes.snowflake:
return updateSnowflake.mutateAsync(credentials as SnowflakeUpdateParams);
case DataSourceTypes.databricks:
return updateDatabricks.mutateAsync(credentials as DatabricksUpdateParams);
case DataSourceTypes.sqlserver:
return updateSQLServer.mutateAsync(credentials as SQLServerUpdateParams);
default:
throw new Error(`Unsupported data source type: ${credentials.type}`);
}
},
isLoading:
updatePostgres.isPending ||
updateMySQL.isPending ||
updateBigQuery.isPending ||
updateRedshift.isPending ||
updateSnowflake.isPending ||
updateDatabricks.isPending ||
updateSQLServer.isPending
};
};

View File

@ -0,0 +1,151 @@
import type { DataSource, DataSourceListItem } from '@/api/asset_interfaces/datasources';
import mainApi from '../instances';
import { DatasourceUpdateParams } from '@/api/request_interfaces/datasources';
export const listDatasources = async () => {
return await mainApi.get<DataSourceListItem[]>('/data_sources').then((res) => res.data);
};
export const getDatasource = async (id: string) => {
return await mainApi.get<DataSource>(`/data_sources/${id}`).then((res) => res.data);
};
export const deleteDatasource = async (id: string) => {
return await mainApi.delete(`/data_sources/${id}`).then((res) => res.data);
};
export const createPostgresDataSource = async (params: {
name: string;
type: 'postgres';
host: string;
port: number;
username: string;
password: string;
default_database: string; //postgres
default_schema: string; //public
}) => {
return mainApi.post<DataSource>('/data_sources', params).then((res) => res.data);
};
export const updatePostgresDataSource = async ({
id,
...params
}: Parameters<typeof createPostgresDataSource>[0] & { id: string }) => {
return mainApi.put<DataSource>(`/data_sources/${id}`, params).then((res) => res.data);
};
export const createMySQLDataSource = async (params: {
name: string;
type: 'mysql' | 'mariadb';
host: string;
port: number;
username: string;
password: string;
default_database: string;
}) => {
return mainApi.post<DataSource>('/data_sources', params).then((res) => res.data);
};
export const updateMySQLDataSource = async ({
id,
...params
}: Parameters<typeof createMySQLDataSource>[0] & { id: string }) => {
return mainApi.put<DataSource>(`/data_sources/${id}`, params).then((res) => res.data);
};
export const createRedshiftDataSource = async (params: {
name: string;
type: 'redshift';
host: string;
port: number;
username: string;
password: string;
default_database: string;
default_schema: string;
}) => {
return mainApi.post<DataSource>('/data_sources', params).then((res) => res.data);
};
export const updateRedshiftDataSource = async ({
id,
...params
}: Parameters<typeof createRedshiftDataSource>[0] & { id: string }) => {
return mainApi.put<DataSource>(`/data_sources/${id}`, params).then((res) => res.data);
};
export const createBigQueryDataSource = async (params: {
name: string;
type: 'bigquery';
service_role_key: string;
default_project_id: string;
default_dataset_id: string;
}) => {
return mainApi.post<DataSource>('/data_sources', params).then((res) => res.data);
};
export const updateBigQueryDataSource = async ({
id,
...params
}: Parameters<typeof createBigQueryDataSource>[0] & { id: string }) => {
return mainApi.put<DataSource>(`/data_sources/${id}`, params).then((res) => res.data);
};
export const createSnowflakeDataSource = async (params: {
name: string;
type: 'snowflake';
account_id: string;
warehouse_id: string;
username: string;
password: string;
role: string | null;
default_database: string;
default_schema: string;
}) => {
return mainApi.post<DataSource>('/data_sources', params).then((res) => res.data);
};
export const updateSnowflakeDataSource = async ({
id,
...params
}: Parameters<typeof createSnowflakeDataSource>[0] & { id: string }) => {
return mainApi.put<DataSource>(`/data_sources/${id}`, params).then((res) => res.data);
};
export const createDatabricksDataSource = async (params: {
name: string;
type: 'databricks';
host: string;
api_key: string;
warehouse_id: string;
default_catalog: string;
default_schema: string;
}) => {
return mainApi.post<DataSource>('/data_sources', params).then((res) => res.data);
};
export const updateDatabricksDataSource = async ({
id,
...params
}: Parameters<typeof createDatabricksDataSource>[0] & { id: string }) => {
return mainApi.put<DataSource>(`/data_sources/${id}`, params).then((res) => res.data);
};
export const createSQLServerDataSource = async (params: {
name: string;
type: 'sqlserver';
host: string;
port: number;
username: string;
password: string;
default_database: string;
default_schema: string;
}) => {
return mainApi.post<DataSource>('/data_sources', params).then((res) => res.data);
};
export const updateSQLServerDataSource = async ({
id,
...params
}: Parameters<typeof createSQLServerDataSource>[0] & { id: string }) => {
return mainApi.put<DataSource>(`/data_sources/${id}`, params).then((res) => res.data);
};

View File

@ -1,74 +0,0 @@
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import {
listDatasources,
getDatasource,
deleteDatasource,
createDatasource,
updateDatasource
} from './requests';
import { queryKeys } from '@/api/query_keys';
import { useBusterNotifications } from '@/context/BusterNotifications';
export const useListDatasources = (enabled: boolean = true) => {
return useQuery({
...queryKeys.datasourceGetList,
queryFn: listDatasources,
enabled
});
};
export const useGetDatasource = (id: string | undefined) => {
return useQuery({
...queryKeys.datasourceGet(id!),
queryFn: () => getDatasource(id!),
enabled: !!id
});
};
export const useDeleteDatasource = () => {
const queryClient = useQueryClient();
const { openConfirmModal } = useBusterNotifications();
const mutationFn = async (dataSourceId: string) => {
await openConfirmModal({
title: 'Delete Data Source',
content: 'Are you sure you want to delete this data source?',
onOk: async () => {
await deleteDatasource(dataSourceId);
}
});
};
return useMutation({
mutationFn,
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: queryKeys.datasourceGetList.queryKey
});
}
});
};
export const useCreateDatasource = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: createDatasource,
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: queryKeys.datasourceGetList.queryKey
});
}
});
};
export const useUpdateDatasource = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: updateDatasource,
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: queryKeys.datasourceGetList.queryKey
});
}
});
};

View File

@ -1,25 +0,0 @@
import type { DataSource, DataSourceListItem } from '@/api/asset_interfaces/datasources';
import mainApi from '../instances';
import { DatasourcePostParams, DatasourceUpdateParams } from '@/api/request_interfaces/datasources';
export const listDatasources = async () => {
return await mainApi.get<DataSourceListItem[]>('/data_sources').then((res) => res.data);
};
export const getDatasource = async (id: string) => {
return await mainApi.get<DataSource>(`/data_sources/${id}`).then((res) => res.data);
};
export const deleteDatasource = async (id: string) => {
return await mainApi.delete(`/data_sources/${id}`).then((res) => res.data);
};
export const createDatasource = async (datasource: DatasourcePostParams) => {
return await mainApi.post<DataSource>('/data_sources', datasource).then((res) => res.data);
};
export const updateDatasource = async (params: DatasourceUpdateParams) => {
return await mainApi
.put<DataSource>(`/data_sources/${params.id}`, params)
.then((res) => res.data);
};

View File

@ -9,7 +9,7 @@ import React from 'react';
import { DataSourceFormContent } from './_DatasourceFormContent';
import { Title, Text } from '@/components/ui/typography';
import { Trash } from '@/components/ui/icons';
import { useDeleteDatasource, useGetDatasource } from '@/api/buster_rest/datasource';
import { useDeleteDatasource, useGetDatasource } from '@/api/buster_rest/data_source';
export const DatasourceForm: React.FC<{ datasourceId: string }> = ({ datasourceId }) => {
const { data: dataSource, isFetched: isFetchedDataSource } = useGetDatasource(datasourceId);

View File

@ -15,7 +15,7 @@ import { DataBricksForm } from './_forms/DataBricksForm';
import { useConfetti } from '@/hooks/useConfetti';
import { SqlServerForm } from './_forms/SqlServerForm';
import { useBusterNotifications } from '@/context/BusterNotifications';
import { useCreateDatasource, useUpdateDatasource } from '@/api/buster_rest/datasource';
import { useCreateDatasource, useUpdateDatasource } from '@/api/buster_rest/data_source';
const FormRecord: Record<
DataSourceTypes,

View File

@ -13,7 +13,7 @@ import { Button } from '@/components/ui/buttons';
import { Dropdown, DropdownItems } from '@/components/ui/dropdown';
import { Plus, Dots, Trash } from '@/components/ui/icons';
import { cn } from '@/lib/classMerge';
import { useDeleteDatasource, useListDatasources } from '@/api/buster_rest/datasource';
import { useDeleteDatasource, useListDatasources } from '@/api/buster_rest/data_source';
import { EmptyStateList, ListEmptyStateWithButton } from '@/components/ui/list';
export const DatasourceList: React.FC = () => {

View File

@ -8,7 +8,7 @@ import { BusterRoutes, createBusterRoute } from '@/routes';
import { useRouter } from 'next/navigation';
import { AppModal } from '@/components/ui/modal';
import { Text } from '@/components/ui/typography';
import { useListDatasources } from '@/api/buster_rest/datasource';
import { useListDatasources } from '@/api/buster_rest/data_source';
const headerConfig = {
title: 'Create a dataset',