diff --git a/pyTigerGraph/__init__.py b/pyTigerGraph/__init__.py index 64282986..7b4172fa 100644 --- a/pyTigerGraph/__init__.py +++ b/pyTigerGraph/__init__.py @@ -2,6 +2,6 @@ from pyTigerGraph.pytgasync.pyTigerGraph import AsyncTigerGraphConnection from pyTigerGraph.common.exception import TigerGraphException -__version__ = "1.8.7" +__version__ = "1.8.8" __license__ = "Apache 2" diff --git a/pyTigerGraph/pyTigerGraphQuery.py b/pyTigerGraph/pyTigerGraphQuery.py index f8751ecf..dce4275f 100644 --- a/pyTigerGraph/pyTigerGraphQuery.py +++ b/pyTigerGraph/pyTigerGraphQuery.py @@ -102,13 +102,75 @@ def getInstalledQueries(self, fmt: str = "py") -> Union[dict, str, 'pd.DataFrame return ret - # TODO installQueries() - # POST /gsql/queries/install - # xref:tigergraph-server:API:built-in-endpoints.adoc#_install_a_query[Install a query] + def installQueries(self, queries: Union[str, list], flag: Union[str, list] = None) -> str: + """Installs one or more queries. - # TODO checkQueryInstallationStatus() - # GET /gsql/queries/install/{request_id} - # xref:tigergraph-server:API:built-in-endpoints.adoc#_check_query_installation_status[Check query installation status] + Args: + queries: + A single query string or a list of query strings to install. Use '*' or 'all' to install all queries. + flag: + Method to install queries. + - '-single' Install the query in single gpr mode. + - '-legacy' Install the query in UDF mode. + - '-debug' Present results contains debug info. + - '-cost' Present results contains performance consumption. + - '-force' Install the query even if it already installed. + + Returns: + The response from the server. + + Endpoints: + GET /gsql/v1/queries/install + See https://docs.tigergraph.com/tigergraph-server/current/api/built-in-endpoints#_install_a_query + """ + logger.info("entry: installQueries") + if logger.level == logging.DEBUG: + logger.debug("params: " + self._locals(locals())) + + params = {} + params["graph"] = self.graphname + if isinstance(queries, list): + queries = ",".join(queries) + params["queries"] = queries + + if flag: + if isinstance(flag, list): + flag = ",".join(flag) + params["flag"] = flag + + ret = self._req("GET", self.gsUrl + "/gsql/v1/queries/install", params=params, authMode="pwd", resKey="") + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(ret)) + logger.info("exit: installQueries") + + return ret + + def getQueryInstallationStatus(self, requestId: str) -> dict: + """Checks the status of query installation. + + Args: + requestId: + The request ID returned from installQueries. + + Returns: + A dictionary containing the installation status. + + Endpoints: + GET /gsql/queries/install/{request_id} + See https://docs.tigergraph.com/tigergraph-server/current/api/built-in-endpoints#_check_query_installation_status + """ + logger.info("entry: getQueryInstallationStatus") + if logger.level == logging.DEBUG: + logger.debug("params: " + self._locals(locals())) + + ret = self._req("GET", self.gsUrl + "/gsql/v1/queries/install&requestid=" + requestId, authMode="pwd", resKey="") + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(ret)) + logger.info("exit: getQueryInstallationStatus") + + return ret def runInstalledQuery(self, queryName: str, params: Union[str, dict] = None, timeout: int = None, sizeLimit: int = None, usePost: bool = False, runAsync: bool = False, diff --git a/pyTigerGraph/pytgasync/pyTigerGraphBase.py b/pyTigerGraph/pytgasync/pyTigerGraphBase.py index b12ea4e9..feef2dcf 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphBase.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphBase.py @@ -134,7 +134,7 @@ async def _req(self, method: str, url: str, authMode: str = "token", headers: di authMode, headers, url, method, data) if "GSQL-TIMEOUT" in _headers: - http_timeout = (10, int(_headers["GSQL-TIMEOUT"]/1000) + 10) + http_timeout = (10, int(int(_headers["GSQL-TIMEOUT"])/1000) + 10) else: http_timeout = None diff --git a/pyTigerGraph/pytgasync/pyTigerGraphQuery.py b/pyTigerGraph/pytgasync/pyTigerGraphQuery.py index 2f497d63..79ff0e20 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphQuery.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphQuery.py @@ -4,6 +4,7 @@ All functions in this module are called as methods on a link:https://docs.tigergraph.com/pytigergraph/current/core-functions/base[`TigerGraphConnection` object]. """ import logging +import time from typing import TYPE_CHECKING, Union, Optional @@ -97,13 +98,84 @@ async def getInstalledQueries(self, fmt: str = "py") -> Union[dict, str, 'pd.Dat return ret - # TODO installQueries() - # POST /gsql/queries/install - # xref:tigergraph-server:API:built-in-endpoints.adoc#_install_a_query[Install a query] + async def installQueries(self, queries: Union[str, list], flag: Union[str, list] = None) -> str: + """Installs one or more queries. - # TODO checkQueryInstallationStatus() - # GET /gsql/queries/install/{request_id} - # xref:tigergraph-server:API:built-in-endpoints.adoc#_check_query_installation_status[Check query installation status] + Args: + queries: + A single query string or a list of query strings to install. Use '*' or 'all' to install all queries. + flag: + Method to install queries. + - '-single' Install the query in single gpr mode. + - '-legacy' Install the query in UDF mode. + - '-debug' Present results contains debug info. + - '-cost' Present results contains performance consumption. + - '-force' Install the query even if it already installed. + + Returns: + The response from the server. + + Endpoints: + GET /gsql/v1/queries/install + See https://docs.tigergraph.com/tigergraph-server/current/api/built-in-endpoints#_install_a_query + """ + logger.info("entry: installQueries") + if logger.level == logging.DEBUG: + logger.debug("params: " + self._locals(locals())) + + params = {} + params["graph"] = self.graphname + if isinstance(queries, list): + queries = ",".join(queries) + params["queries"] = queries + + if flag: + if isinstance(flag, list): + flag = ",".join(flag) + params["flag"] = flag + + request_id = await self._req("GET", self.gsUrl + "/gsql/v1/queries/install", params=params, authMode="pwd", resKey="requestId") + + ret = None + while not ret: + ret = await self._req("GET", self.gsUrl + "/gsql/v1/queries/install/" + str(request_id), authMode="pwd", resKey="") + if "SUCCESS" in ret["message"] or "FAILED" in ret["message"]: + break + else: + ret = None + time.sleep(1) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(ret)) + logger.info("exit: installQueries") + + return ret + + async def getQueryInstallationStatus(self, requestId: str) -> dict: + """Get the status of query installation. + + Args: + requestId: + The request ID returned from installQueries. + + Returns: + A dictionary containing the installation status. + + Endpoints: + GET /gsql/queries/install/{request_id} + See https://docs.tigergraph.com/tigergraph-server/current/api/built-in-endpoints#_check_query_installation_status + """ + logger.info("entry: getQueryInstallationStatus") + if logger.level == logging.DEBUG: + logger.debug("params: " + self._locals(locals())) + + ret = await self._req("GET", self.gsUrl + "/gsql/v1/queries/install&requestid=" + requestId, authMode="pwd") + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(ret)) + logger.info("exit: getQueryInstallationStatus") + + return ret async def runInstalledQuery(self, queryName: str, params: Union[str, dict] = None, timeout: int = None, sizeLimit: int = None, usePost: bool = False, runAsync: bool = False, diff --git a/tests/test_pyTigerGraphQuery.py b/tests/test_pyTigerGraphQuery.py index 9f752227..c60d1d9e 100644 --- a/tests/test_pyTigerGraphQuery.py +++ b/tests/test_pyTigerGraphQuery.py @@ -158,6 +158,98 @@ def test_11_queryDescriptions(self): self.assertEqual( "This function is only supported on versions of TigerGraph >= 4.0.0.", tge.exception.message) + def test_installQueries(self): + # First create the queries using gsql + queries = [ + """ + CREATE QUERY test_install_query() { + PRINT "Hello World"; + } + """, + """ + CREATE QUERY test_install_query1() { + PRINT "Hello World 1"; + } + """, + """ + CREATE QUERY test_install_query2() { + PRINT "Hello World 2"; + } + """, + """ + CREATE QUERY test_install_query_with_flag() { + PRINT "Hello World"; + } + """, + """ + CREATE QUERY test_install_query_with_multiple_flags() { + PRINT "Hello World"; + } + """ + ] + + # Create all queries first + for query in queries: + self.conn.gsql(query) + + # Test installing a single query + requestId = self.conn.installQueries("test_install_query") + self.assertIsInstance(requestId, str) + + # Check installation status + status = self.conn.getQueryInstallationStatus(requestId) + self.assertIn("message", status) + self.assertIn(status["message"], "success") + + # Test installing multiple queries + requestId = self.conn.installQueries(["test_install_query1", "test_install_query2"]) + self.assertIsInstance(requestId, str) + + # Check installation status + status = self.conn.getQueryInstallationStatus(requestId) + self.assertIn("message", status) + self.assertIn(status["message"], "SUCCESS") + + # Test installing with flags + requestId = self.conn.installQueries("test_install_query_with_flag", flag="-force") + self.assertIsInstance(requestId, str) + + # Check installation status + status = self.conn.getQueryInstallationStatus(requestId) + self.assertIn("message", status) + self.assertIn(status["message"], "SUCCESS") + + # Test installing with multiple flags + requestId = self.conn.installQueries("test_install_query_with_multiple_flags", flag=["-force", "-debug"]) + self.assertIsInstance(requestId, str) + + # Check installation status + status = self.conn.getQueryInstallationStatus(requestId) + self.assertIn("message", status) + self.assertIn(status["message"], "SUCCESS") + + # Test installing all queries + requestId = self.conn.installQueries("all") + self.assertIsInstance(requestId, str) + + # Check installation status + status = self.conn.getQueryInstallationStatus(requestId) + self.assertIn("message", status) + self.assertIn(status["message"], "SUCCESS") + + # Test installing all queries with asterisk + requestId = self.conn.installQueries("*") + self.assertIsInstance(requestId, str) + + # Check installation status + status = self.conn.getQueryInstallationStatus(requestId) + self.assertIn("message", status) + self.assertIn(status["message"], "SUCCESS") + + # Test invalid query name + with self.assertRaises(ValueError): + self.conn.installQueries("non_existent_query") + if __name__ == '__main__': unittest.main() diff --git a/tests/test_pyTigerGraphQueryAsync.py b/tests/test_pyTigerGraphQueryAsync.py index d983c39c..b3951931 100644 --- a/tests/test_pyTigerGraphQueryAsync.py +++ b/tests/test_pyTigerGraphQueryAsync.py @@ -161,6 +161,68 @@ async def test_11_queryDescriptions(self): self.assertEqual( "This function is only supported on versions of TigerGraph >= 4.0.0.", tge.exception.message) + async def test_04_installQueries(self): + # First create the queries using gsql + queries = [ + """ + CREATE QUERY test_install_query_async() { + PRINT "Hello World"; + } + """, + """ + CREATE QUERY test_install_query1_async() { + PRINT "Hello World 1"; + } + """, + """ + CREATE QUERY test_install_query2_async() { + PRINT "Hello World 2"; + } + """, + """ + CREATE QUERY test_install_query_with_flag_async() { + PRINT "Hello World"; + } + """, + """ + CREATE QUERY test_install_query_with_multiple_flags_async() { + PRINT "Hello World"; + } + """ + ] + + # Create all queries first + for query in queries: + await self.conn.gsql(query) + + # Test installing a single query + result = await self.conn.installQueries("test_install_query_async") + self.assertIn("SUCCESS", result) + + # Test installing multiple queries + result = await self.conn.installQueries(["test_install_query1_async", "test_install_query2_async"]) + self.assertIn("SUCCESS", result) + + # Test installing with flags + result = await self.conn.installQueries("test_install_query_with_flag_async", flag="-force") + self.assertIn("SUCCESS", result) + + # Test installing with multiple flags + result = await self.conn.installQueries("test_install_query_with_multiple_flags_async", flag=["-force", "-debug"]) + self.assertIn("SUCCESS", result) + + # Test installing all queries + result = await self.conn.installQueries("all") + self.assertIn("SUCCESS", result) + + # Test installing all queries with asterisk + result = await self.conn.installQueries("*") + self.assertIn("SUCCESS", result) + + # Test invalid query name + with self.assertRaises(ValueError): + await self.conn.installQueries("non_existent_query") + if __name__ == '__main__': unittest.main()