-
Notifications
You must be signed in to change notification settings - Fork 74
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[535] Implement basic support for GenQuery2
- Loading branch information
Showing
6 changed files
with
195 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import json | ||
|
||
from irods.api_number import api_number | ||
from irods.exception import OperationNotSupported | ||
from irods.message import GenQuery2Request, STR_PI, iRODSMessage | ||
|
||
|
||
class GenQuery2(object): | ||
"""Interface to the GenQuery2 API | ||
This class provides an interface to the GenQuery2 API, an experimental | ||
iRODS API for querying iRODS. GenQuery2 is an improved version of the | ||
traditional GenQuery interface. The GenQuery2 interface may be subject | ||
to change. | ||
""" | ||
|
||
def __init__(self, session): | ||
self.session = session | ||
if not self._is_supported(): | ||
raise OperationNotSupported( | ||
"GenQuery2 is not supported by default on this iRODS version.") | ||
|
||
def execute(self, query, zone=None): | ||
"""Execute this GenQuery2 query, and return the results.""" | ||
effective_zone = self.session.zone if zone is None else zone | ||
return json.loads(self._exec_genquery2(query, effective_zone)) | ||
|
||
def get_sql(self, query, zone=None): | ||
"""Return the SQL query that this GenQuery2 query will be translated to.""" | ||
effective_zone = self.session.zone if zone is None else zone | ||
return self._exec_genquery2(query, effective_zone, sql_flag=True) | ||
|
||
def get_column_mappings(self, zone=None): | ||
effective_zone = self.session.zone if zone is None else zone | ||
return json.loads(self._exec_genquery2( | ||
"", effective_zone, column_mappings_flag=True)) | ||
|
||
def _exec_genquery2(self, query, zone, sql_flag=False, | ||
column_mappings_flag=False): | ||
msg = GenQuery2Request() | ||
msg.query_string = query | ||
msg.zone = zone | ||
msg.sql_only = 1 if sql_flag else 0 | ||
msg.column_mappings = 1 if column_mappings_flag else 0 | ||
message = iRODSMessage('RODS_API_REQ', | ||
msg=msg, | ||
int_info=api_number['GENQUERY2_AN']) | ||
with self.session.pool.get_connection() as conn: | ||
conn.send(message) | ||
response = conn.recv() | ||
return response.get_main_message(STR_PI).myStr | ||
|
||
def _is_supported(self): | ||
"""Checks whether this iRODS server supports GenQuery2.""" | ||
return self.session.server_version >= (4, 3, 2) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import unittest | ||
|
||
import irods.test.helpers as helpers | ||
|
||
|
||
class TestGenQuery2(unittest.TestCase): | ||
|
||
def setUp(self): | ||
self.sess = helpers.make_session() | ||
|
||
if self.sess.server_version < (4, 3, 2): | ||
self.skipTest( | ||
'GenQuery2 is not available by default in iRODS before v4.3.2.') | ||
|
||
self.coll_path_a = '/{}/home/{}/test_query2_coll_a'.format( | ||
self.sess.zone, self.sess.username) | ||
self.coll_path_b = '/{}/home/{}/test_query2_coll_b'.format( | ||
self.sess.zone, self.sess.username) | ||
self.sess.collections.create(self.coll_path_a) | ||
self.sess.collections.create(self.coll_path_b) | ||
|
||
def tearDown(self): | ||
'''Remove test data and close connections | ||
''' | ||
self.sess.collections.remove(self.coll_path_a, force=True) | ||
self.sess.collections.remove(self.coll_path_b, force=True) | ||
self.sess.cleanup() | ||
|
||
def test_select(self): | ||
query = "SELECT COLL_NAME WHERE COLL_NAME = '{}'".format( | ||
self.coll_path_a) | ||
q = self.sess.genquery2_object() | ||
query_result = q.execute(query) | ||
query_sql = q.get_sql(query) | ||
self.assertIn([self.coll_path_a], query_result) | ||
self.assertEqual(len(query_result), 1) | ||
self.assertEqual(query_sql, "select distinct t0.coll_name from R_COLL_MAIN t0 inner join R_OBJT_ACCESS pcoa on t0.coll_id = pcoa.object_id inner join R_TOKN_MAIN pct on pcoa.access_type_id = pct.token_id inner join R_USER_MAIN pcu on pcoa.user_id = pcu.user_id where t0.coll_name = ? and pcoa.access_type_id >= 1000 fetch first 256 rows only") | ||
|
||
def test_select_with_explicit_zone(self): | ||
query = "SELECT COLL_NAME WHERE COLL_NAME = '{}'".format( | ||
self.coll_path_a) | ||
q = self.sess.genquery2_object() | ||
query_result = q.execute(query, zone=self.sess.zone) | ||
query_sql = q.get_sql(query, zone=self.sess.zone) | ||
self.assertIn([self.coll_path_a], query_result) | ||
self.assertEqual(len(query_result), 1) | ||
self.assertEqual(query_sql, "select distinct t0.coll_name from R_COLL_MAIN t0 inner join R_OBJT_ACCESS pcoa on t0.coll_id = pcoa.object_id inner join R_TOKN_MAIN pct on pcoa.access_type_id = pct.token_id inner join R_USER_MAIN pcu on pcoa.user_id = pcu.user_id where t0.coll_name = ? and pcoa.access_type_id >= 1000 fetch first 256 rows only") | ||
|
||
def test_select_with_shorthand(self): | ||
query = "SELECT COLL_NAME WHERE COLL_NAME = '{}'".format( | ||
self.coll_path_a) | ||
query_result = self.sess.genquery2(query) | ||
self.assertIn([self.coll_path_a], query_result) | ||
self.assertEqual(len(query_result), 1) | ||
|
||
def test_select_with_shorthand_and_explicit_zone(self): | ||
query = "SELECT COLL_NAME WHERE COLL_NAME = '{}'".format( | ||
self.coll_path_a) | ||
query_result = self.sess.genquery2(query, zone=self.sess.zone) | ||
self.assertIn([self.coll_path_a], query_result) | ||
self.assertEqual(len(query_result), 1) | ||
|
||
def test_select_or(self): | ||
query = "SELECT COLL_NAME WHERE COLL_NAME = '{}' OR COLL_NAME = '{}'".format( | ||
self.coll_path_a, self.coll_path_b) | ||
q = self.sess.genquery2_object() | ||
query_result = q.execute(query) | ||
query_sql = q.get_sql(query) | ||
self.assertIn([self.coll_path_a], query_result) | ||
self.assertIn([self.coll_path_b], query_result) | ||
self.assertEqual(len(query_result), 2) | ||
self.assertEqual(query_sql, "select distinct t0.coll_name from R_COLL_MAIN t0 inner join R_OBJT_ACCESS pcoa on t0.coll_id = pcoa.object_id inner join R_TOKN_MAIN pct on pcoa.access_type_id = pct.token_id inner join R_USER_MAIN pcu on pcoa.user_id = pcu.user_id where t0.coll_name = ? or t0.coll_name = ? and pcoa.access_type_id >= 1000 fetch first 256 rows only") | ||
|
||
def test_select_and(self): | ||
query = "SELECT COLL_NAME WHERE COLL_NAME LIKE '{}' AND COLL_NAME LIKE '{}'".format( | ||
"%test_query2_coll%", "%query2_coll_a%") | ||
q = self.sess.genquery2_object() | ||
query_result = q.execute(query) | ||
query_sql = q.get_sql(query) | ||
self.assertIn([self.coll_path_a], query_result) | ||
self.assertEqual(len(query_result), 1) | ||
self.assertEqual(query_sql, "select distinct t0.coll_name from R_COLL_MAIN t0 inner join R_OBJT_ACCESS pcoa on t0.coll_id = pcoa.object_id inner join R_TOKN_MAIN pct on pcoa.access_type_id = pct.token_id inner join R_USER_MAIN pcu on pcoa.user_id = pcu.user_id where t0.coll_name like ? and t0.coll_name like ? and pcoa.access_type_id >= 1000 fetch first 256 rows only") | ||
|
||
def test_column_mappings(self): | ||
q = self.sess.genquery2_object() | ||
result = q.get_column_mappings() | ||
self.assertIn("COLL_ID", result.keys()) | ||
self.assertIn("DATA_ID", result.keys()) | ||
self.assertIn("RESC_ID", result.keys()) | ||
self.assertIn("USER_ID", result.keys()) |