Bläddra i källkod

HUE-7738 [editor] Add pub sub events for describing individual UDFs

Johan Ahlen 5 år sedan
förälder
incheckning
421231651e

+ 49 - 18
desktop/core/src/desktop/js/sql/reference/apiUtils.ts

@@ -15,7 +15,7 @@
 // limitations under the License.
 
 import { simplePostAsync } from 'api/apiUtils';
-import { AUTOCOMPLETE_API_PREFIX } from 'api/urls';
+import { AUTOCOMPLETE_API_PREFIX, DESCRIBE_API_PREFIX } from 'api/urls';
 import { UdfArgument, UdfDetails } from 'sql/reference/types';
 import { Connector } from 'types';
 import I18n from 'utils/i18n';
@@ -26,8 +26,10 @@ export interface ApiUdf {
   is_persistent?: string;
   return_type?: string;
   signature?: string;
+  description?: string;
 }
 
+const FUNCTION_OPERATION = 'function';
 const FUNCTIONS_OPERATION = 'functions';
 const DEFAULT_DESCRIPTION = I18n('No description available.');
 const DEFAULT_RETURN_TYPES = ['T'];
@@ -46,7 +48,8 @@ const adaptApiUdf = (apiUdf: ApiUdf): UdfDetails => {
     arguments: extractArgumentTypes(apiUdf),
     signature: signature,
     draggable: signature,
-    description: DEFAULT_DESCRIPTION
+    description: DEFAULT_DESCRIPTION,
+    described: false
   };
 };
 
@@ -120,29 +123,57 @@ export const adaptApiFunctions = (functions: ApiUdf[]): UdfDetails[] => {
   return udfs;
 };
 
-export const fetchUdfs = async (options: {
-  connector: Connector;
-  database?: string;
-  silenceErrors: boolean;
-}): Promise<UdfDetails[]> => {
-  let url = AUTOCOMPLETE_API_PREFIX;
-  if (options.database) {
-    url += '/' + options.database;
+const createUrl = (database?: string, udf?: UdfDetails): string => {
+  if (database && udf) {
+    return `${AUTOCOMPLETE_API_PREFIX}${database}/${udf.name}`;
   }
+  if (database) {
+    return `${AUTOCOMPLETE_API_PREFIX}${database}`;
+  }
+  if (udf) {
+    return `${AUTOCOMPLETE_API_PREFIX}${udf.name}`;
+  }
+  return AUTOCOMPLETE_API_PREFIX;
+};
 
-  const data = {
-    notebook: {},
-    snippet: JSON.stringify({
-      type: options.connector.id
-    }),
-    operation: FUNCTIONS_OPERATION
-  };
+const createRequestData = (connector: Connector, operation: string) => ({
+  notebook: {},
+  snippet: JSON.stringify({
+    type: connector.id
+  }),
+  operation: operation
+});
+
+export const fetchUdfs = async (
+  connector: Connector,
+  database?: string,
+  silenceErrors = true
+): Promise<UdfDetails[]> => {
+  const url = createUrl(database);
+  const data = createRequestData(connector, FUNCTIONS_OPERATION);
 
   try {
-    const response = await simplePostAsync(url, data, options);
+    const response = await simplePostAsync(url, data, { silenceErrors: silenceErrors });
     if (response && response.functions) {
       return adaptApiFunctions(response.functions);
     }
   } catch (err) {}
   return [];
 };
+
+export const fetchDescribe = async (
+  connector: Connector,
+  udf: UdfDetails,
+  database?: string,
+  silenceErrors = true
+): Promise<ApiUdf | undefined> => {
+  const url = createUrl(database, udf);
+  const data = createRequestData(connector, FUNCTION_OPERATION);
+
+  try {
+    const response = await simplePostAsync(url, data, { silenceErrors: silenceErrors });
+    if (response && response.function) {
+      return response.function;
+    }
+  } catch (err) {}
+};

+ 58 - 8
desktop/core/src/desktop/js/sql/reference/sqlReferenceRepository.ts

@@ -14,15 +14,23 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-import { SetOptions, UdfArgument, UdfCategory, UdfCategoryFunctions, UdfDetails} from 'sql/reference/types';
+import {
+  SetOptions,
+  UdfArgument,
+  UdfCategory,
+  UdfCategoryFunctions,
+  UdfDetails
+} from 'sql/reference/types';
 import { Connector } from 'types';
 import { matchesType } from './typeUtils';
 import I18n from 'utils/i18n';
 import huePubSub from 'utils/huePubSub';
 import { clearUdfCache, getCachedUdfCategories, setCachedUdfCategories } from './apiCache';
-import { fetchUdfs } from './apiUtils';
+import { fetchDescribe, fetchUdfs } from './apiUtils';
 
 export const CLEAR_UDF_CACHE_EVENT = 'hue.clear.udf.cache';
+export const DESCRIBE_UDF_EVENT = 'hue.describe.udf';
+export const UDF_DESCRIBED_EVENT = 'hue.udf.described';
 
 const SET_REFS: { [attr: string]: () => Promise<{ SET_OPTIONS?: SetOptions }> } = {
   // @ts-ignore
@@ -69,7 +77,6 @@ const findUdfsToAdd = (
   const result: UdfCategoryFunctions = {};
 
   apiUdfs.forEach(apiUdf => {
-    // TODO: Impala reports the same UDF multiple times, once per argument type.
     if (
       !result[apiUdf.name] &&
       !existingUdfNames.has(apiUdf.name.toUpperCase()) &&
@@ -87,11 +94,7 @@ const mergeWithApiUdfs = async (
   connector: Connector,
   database?: string
 ) => {
-  const apiUdfs = await fetchUdfs({
-    connector: connector,
-    database: database,
-    silenceErrors: true
-  });
+  const apiUdfs = await fetchUdfs(connector, database);
 
   if (apiUdfs.length) {
     const additionalUdfs = findUdfsToAdd(apiUdfs, categories);
@@ -121,6 +124,11 @@ export const getUdfCategories = async (
         const module = await UDF_REFS[connector.dialect]();
         if (module.UDF_CATEGORIES) {
           categories = module.UDF_CATEGORIES;
+          categories.forEach(category => {
+            Object.values(category.functions).forEach(udf => {
+              udf.described = true;
+            });
+          });
         }
       }
       await mergeWithApiUdfs(categories, connector, database);
@@ -229,6 +237,48 @@ export const getSetOptions = async (connector: Connector): Promise<SetOptions> =
   return {};
 };
 
+const findUdfInCategories = (
+  categories: UdfCategory[],
+  udfName: string
+): UdfDetails | undefined => {
+  let foundUdf = undefined;
+  categories.some(category =>
+    Object.values(category.functions).some(udf => {
+      if (udf.name === udfName) {
+        foundUdf = udf;
+        return true;
+      }
+    })
+  );
+  return foundUdf;
+};
+
+huePubSub.subscribe(
+  DESCRIBE_UDF_EVENT,
+  async (details: { connector: Connector; udfName: string; database?: string }): Promise<void> => {
+    const categories = await getUdfCategories(details.connector, details.database);
+    const foundUdf = findUdfInCategories(categories, details.udfName);
+    if (foundUdf && !foundUdf.described) {
+      const apiUdf = await fetchDescribe(details.connector, foundUdf, details.database);
+      if (apiUdf) {
+        if (apiUdf.description) {
+          foundUdf.description = apiUdf.description;
+        }
+        if (apiUdf.signature) {
+          foundUdf.signature = apiUdf.signature;
+        }
+        foundUdf.described = true;
+        await setCachedUdfCategories(details.connector, details.database, categories);
+        huePubSub.publish(UDF_DESCRIBED_EVENT, {
+          connector: details.connector,
+          database: details.database,
+          udf: foundUdf
+        });
+      }
+    }
+  }
+);
+
 huePubSub.subscribe(
   CLEAR_UDF_CACHE_EVENT,
   async (details: { connector: Connector; callback: () => void }) => {

+ 1 - 0
desktop/core/src/desktop/js/sql/reference/types.ts

@@ -29,6 +29,7 @@ export interface UdfDetails {
   signature: string;
   draggable: string;
   description?: string;
+  described?: boolean;
 }
 
 export interface UdfCategoryFunctions {