client/app/components/queries/editor-components/databricks/useDatabricksSchema.js (107 lines of code) (raw):

import { has, get, first, isFunction } from "lodash"; import { useEffect, useState, useMemo, useCallback, useRef } from "react"; import notification from "@/services/notification"; import DatabricksDataSource from "@/services/databricks-data-source"; function getDatabases(dataSource) { if (!dataSource) { return Promise.resolve([]); } return DatabricksDataSource.getDatabases(dataSource).catch(() => { notification.error("Failed to load Database list", "Please try again later."); return Promise.resolve([]); }); } function getSchema(dataSource, databaseName) { if (!dataSource || !databaseName) { return Promise.resolve([]); } return DatabricksDataSource.getDatabaseTables(dataSource, databaseName).catch(() => { notification.error("Failed to load Schema", "Please try again later."); return Promise.resolve([]); }); } export default function useDatabricksSchema(dataSource, options = null, onOptionsUpdate = null) { const [databases, setDatabases] = useState([]); const [loadingDatabases, setLoadingDatabases] = useState(true); const [currentDatabaseName, setCurrentDatabaseName] = useState(); const [schemas, setSchemas] = useState({}); const [loadingSchema, setLoadingSchema] = useState(false); const schema = useMemo(() => get(schemas, currentDatabaseName, []), [schemas, currentDatabaseName]); const schemasRef = useRef(); schemasRef.current = schemas; useEffect(() => { let isCancelled = false; if (currentDatabaseName && !has(schemasRef.current, currentDatabaseName)) { setLoadingSchema(true); getSchema(dataSource, currentDatabaseName) .then(data => { if (!isCancelled) { setSchemas(currentSchemas => ({ ...currentSchemas, [currentDatabaseName]: data, })); } }) .finally(() => { if (!isCancelled) { setLoadingSchema(false); } }); } return () => { isCancelled = true; }; }, [dataSource, currentDatabaseName]); const defaultDatabaseNameRef = useRef(); defaultDatabaseNameRef.current = get(options, "selectedDatabase", null); useEffect(() => { let isCancelled = false; setLoadingDatabases(true); getDatabases(dataSource) .then(data => { if (!isCancelled) { setDatabases(data); setCurrentDatabaseName( defaultDatabaseNameRef.current || localStorage.getItem(`lastSelectedDatabricksDatabase_${dataSource.id}`) || first(data) || null ); } }) .finally(() => { if (!isCancelled) { setLoadingDatabases(false); } }); return () => { isCancelled = true; }; }, [dataSource]); const setCurrentDatabase = useCallback( databaseName => { if (databaseName) { try { localStorage.setItem(`lastSelectedDatabricksDatabase_${dataSource.id}`, databaseName); } catch (e) { // `localStorage.setItem` may throw exception if there are no enough space - in this case it could be ignored } } setCurrentDatabaseName(databaseName); if (isFunction(onOptionsUpdate) && databaseName !== defaultDatabaseNameRef.current) { onOptionsUpdate({ ...options, selectedDatabase: databaseName, }); } }, [dataSource.id, options, onOptionsUpdate] ); return { databases, loadingDatabases, schema, loadingSchema, currentDatabaseName, setCurrentDatabase, }; }