From 38b79b38c0bcc9ee8af492c4d010705b22523af0 Mon Sep 17 00:00:00 2001 From: Rudra Date: Fri, 23 Oct 2026 13:18:34 +0530 Subject: [PATCH] [#841] fix wrong column names in the DataAccess model The icat_key strings of the DataAccess columns 701-704 carried the "COL_" prefix, inconsistent with DataAccess.type (700: DATA_ACCESS_TYPE) and with the iRODS genquery1 attribute strings defined in lib/core/include/irods/rodsGenQueryNames.h of the iRODS server (DATA_ACCESS_NAME, DATA_TOKEN_NAMESPACE, DATA_ACCESS_USER_ID, DATA_ACCESS_DATA_ID - the COL_ prefix belongs only to the "#" define identifiers, not to the attribute strings). The mismatch was reported to surface in client-side criteria and result row lookups (Criterion('=', DataAccess.name, 'own'); row[DataAccess.name / DataAccess.user_id]) as described in issue #841. Signed-off-by: Rudra --- irods/models.py | 8 +- ...test_dataaccess_column_names__issue_841.py | 84 +++++++++++++++++++ 2 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 irods/test/modules/test_dataaccess_column_names__issue_841.py diff --git a/irods/models.py b/irods/models.py index 99df3db55..599d3bc6c 100644 --- a/irods/models.py +++ b/irods/models.py @@ -173,10 +173,10 @@ class UserMeta(Model): class DataAccess(Model): type = Column(Integer, "DATA_ACCESS_TYPE", 700) - name = Column(String, "COL_DATA_ACCESS_NAME", 701) - token_namespace = Column(String, "COL_DATA_TOKEN_NAMESPACE", 702) - user_id = Column(Integer, "COL_DATA_ACCESS_USER_ID", 703) - data_id = Column(Integer, "COL_DATA_ACCESS_DATA_ID", 704) + name = Column(String, "DATA_ACCESS_NAME", 701) + token_namespace = Column(String, "DATA_TOKEN_NAMESPACE", 702) + user_id = Column(Integer, "DATA_ACCESS_USER_ID", 703) + data_id = Column(Integer, "DATA_ACCESS_DATA_ID", 704) class CollectionAccess(Model): diff --git a/irods/test/modules/test_dataaccess_column_names__issue_841.py b/irods/test/modules/test_dataaccess_column_names__issue_841.py new file mode 100644 index 000000000..26e87a593 --- /dev/null +++ b/irods/test/modules/test_dataaccess_column_names__issue_841.py @@ -0,0 +1,84 @@ +"""Regression tests for issue #841 (wrong column names in the DataAccess model).""" +import unittest +from collections import OrderedDict + +from irods.column import Criterion +from irods.message import empty_gen_query_out +from irods.models import Collection, DataAccess, DataObject, ModelBase +from irods.query import Query +from irods.results import ResultSet + + +class _SessionStateStub: + """Provide sess.server_version == (4, 3, 4) for building a genquery offline (no server).""" + + server_version = (4, 3, 4) + + +# The strings iRODS itself defines as genquery1 column attributes; see +# lib/core/include/irods/rodsGenQueryNames.h in the iRODS server sources, +# where COL_DATA_ACCESS_NAME (the "#" define / C identifier) maps to the +# attribute string "DATA_ACCESS_NAME", COL_DATA_TOKEN_NAMESPACE to +# "DATA_TOKEN_NAMESPACE", etc. Attribute strings carry no "COL_" prefix; +# the DataObject/Collection/RuleExec/... models in irods/models.py follow +# this convention, and DataAccess.type (700) already did. +# +# Attempting a permission criterion from DataAccess as described in issue +# #841 (Criterion('=', DataAccess.name, 'own')) previously carried the +# mismatched "COL_"-prefixed names. +_IRODS_ATTRIBUTE_NAMES = OrderedDict( + [ + (DataAccess.type, "DATA_ACCESS_TYPE"), + (DataAccess.name, "DATA_ACCESS_NAME"), + (DataAccess.token_namespace, "DATA_TOKEN_NAMESPACE"), + (DataAccess.user_id, "DATA_ACCESS_USER_ID"), + (DataAccess.data_id, "DATA_ACCESS_DATA_ID"), + ] +) + +_DATAACCESS_COLUMN_IDS = {700, 701, 702, 703, 704} + + +class TestDataAccessColumnNames(unittest.TestCase): + """DataAccess model columns carry their iRODS genquery1 attribute names.""" + + def test_dataaccess_request_columns_use_irods_attribute_names(self): + """DataAccess columns built into a client-side genquery carry iRODS attribute names.""" + query = Query(_SessionStateStub(), DataObject.name, Collection.name, DataAccess) + selected_ids = {c.icat_id for c in query.columns} + self.assertGreaterEqual(selected_ids, _DATAACCESS_COLUMN_IDS) + + for column, expected_name in _IRODS_ATTRIBUTE_NAMES.items(): + self.assertEqual( + column.icat_key, expected_name, f"{column!r} should be {expected_name!r} (got {column.icat_key!r})" + ) + + def test_criteria_built_from_dataaccess_columns_use_irods_attribute_names(self): + """Criteria like Criterion("=", DataAccess.name, "own") are built on iRODS-named columns.""" + for attribute, expected in _IRODS_ATTRIBUTE_NAMES.items(): + criterion = Criterion("=", attribute, "own") + self.assertEqual(criterion.query_key.icat_key, expected) + + def test_result_keys_surface_irods_attribute_names(self): + """Result rows keyed via ModelBase.columns()[attriInx] surface the iRODS attribute names (results.py).""" + query = Query(_SessionStateStub(), DataAccess) + raw = empty_gen_query_out(list(query.columns.keys())) + result = ResultSet(raw) + keys = {c.attriInx: ModelBase.columns()[c.attriInx] for c in result.cols} + self.assertEqual(set(keys), _DATAACCESS_COLUMN_IDS) + for column, expected_name in _IRODS_ATTRIBUTE_NAMES.items(): + self.assertEqual(keys[column.icat_id].icat_key, expected_name) + self.assertEqual(keys[column.icat_id], column) + + def test_no_dataaccess_column_name_carries_the_col_prefix(self): + """No DataAccess column name keeps the COL_ prefix (700 already had none; #841).""" + columns_by_id = { + DataAccess.type.icat_id: DataAccess.type, + DataAccess.name.icat_id: DataAccess.name, + DataAccess.token_namespace.icat_id: DataAccess.token_namespace, + DataAccess.user_id.icat_id: DataAccess.user_id, + DataAccess.data_id.icat_id: DataAccess.data_id, + } + self.assertEqual(set(columns_by_id), _DATAACCESS_COLUMN_IDS) + for column in columns_by_id.values(): + self.assertFalse(column.icat_key.startswith("COL_"), f"unexpected 'COL_' prefix in {column!r}")