@@ -706,3 +706,142 @@ def delete_alternate_key(self, table: str, key_id: str) -> None:
706706 """
707707 with self ._client ._scoped_odata () as od :
708708 od ._delete_alternate_key (table , key_id )
709+
710+ # -------------------------------------------------------- list_columns
711+
712+ def list_columns (
713+ self ,
714+ table : str ,
715+ * ,
716+ select : Optional [List [str ]] = None ,
717+ filter : Optional [str ] = None ,
718+ ) -> List [Dict [str , Any ]]:
719+ """List all attribute (column) definitions for a table.
720+
721+ :param table: Schema name of the table (e.g. ``"account"`` or
722+ ``"new_Product"``).
723+ :type table: :class:`str`
724+ :param select: Optional list of property names to project via
725+ ``$select``. Values are passed as-is (PascalCase).
726+ :type select: :class:`list` of :class:`str` or None
727+ :param filter: Optional OData ``$filter`` expression. For example,
728+ ``"AttributeType eq 'String'"`` returns only string columns.
729+ :type filter: :class:`str` or None
730+
731+ :return: List of raw attribute metadata dictionaries.
732+ :rtype: :class:`list` of :class:`dict`
733+
734+ :raises ~PowerPlatform.Dataverse.core.errors.MetadataError:
735+ If the table is not found.
736+ :raises ~PowerPlatform.Dataverse.core.errors.HttpError:
737+ If the Web API request fails.
738+
739+ Example::
740+
741+ # List all columns on the account table
742+ columns = client.tables.list_columns("account")
743+ for col in columns:
744+ print(f"{col['LogicalName']} ({col.get('AttributeType')})")
745+
746+ # List only specific properties
747+ columns = client.tables.list_columns(
748+ "account",
749+ select=["LogicalName", "SchemaName", "AttributeType"],
750+ )
751+
752+ # Filter to only string attributes
753+ columns = client.tables.list_columns(
754+ "account",
755+ filter="AttributeType eq 'String'",
756+ )
757+ """
758+ with self ._client ._scoped_odata () as od :
759+ return od ._list_columns (table , select = select , filter = filter )
760+
761+ # ------------------------------------------------- list_relationships
762+
763+ def list_relationships (
764+ self ,
765+ * ,
766+ filter : Optional [str ] = None ,
767+ select : Optional [List [str ]] = None ,
768+ ) -> List [Dict [str , Any ]]:
769+ """List all relationship definitions in the environment.
770+
771+ :param filter: Optional OData ``$filter`` expression. For example,
772+ ``"RelationshipType eq Microsoft.Dynamics.CRM.RelationshipType'OneToManyRelationship'"``
773+ returns only one-to-many relationships.
774+ :type filter: :class:`str` or None
775+ :param select: Optional list of property names to project via
776+ ``$select``. Values are passed as-is (PascalCase).
777+ :type select: :class:`list` of :class:`str` or None
778+
779+ :return: List of raw relationship metadata dictionaries.
780+ :rtype: :class:`list` of :class:`dict`
781+
782+ :raises ~PowerPlatform.Dataverse.core.errors.HttpError:
783+ If the Web API request fails.
784+
785+ Example::
786+
787+ # List all relationships
788+ rels = client.tables.list_relationships()
789+ for rel in rels:
790+ print(f"{rel['SchemaName']} ({rel.get('@odata.type')})")
791+
792+ # Filter by type
793+ one_to_many = client.tables.list_relationships(
794+ filter="RelationshipType eq Microsoft.Dynamics.CRM.RelationshipType'OneToManyRelationship'"
795+ )
796+
797+ # Select specific properties
798+ rels = client.tables.list_relationships(
799+ select=["SchemaName", "ReferencedEntity", "ReferencingEntity"]
800+ )
801+ """
802+ with self ._client ._scoped_odata () as od :
803+ return od ._list_relationships (filter = filter , select = select )
804+
805+ # --------------------------------------------- list_table_relationships
806+
807+ def list_table_relationships (
808+ self ,
809+ table : str ,
810+ * ,
811+ filter : Optional [str ] = None ,
812+ select : Optional [List [str ]] = None ,
813+ ) -> List [Dict [str , Any ]]:
814+ """List all relationships for a specific table.
815+
816+ Combines one-to-many and many-to-many relationships for the given
817+ table by querying both
818+ ``EntityDefinitions({id})/OneToManyRelationships`` and
819+ ``EntityDefinitions({id})/ManyToManyRelationships``.
820+
821+ :param table: Schema name of the table (e.g. ``"account"``).
822+ :type table: :class:`str`
823+ :param filter: Optional OData ``$filter`` expression applied to each
824+ sub-request.
825+ :type filter: :class:`str` or None
826+ :param select: Optional list of property names to project via
827+ ``$select``. Values are passed as-is (PascalCase).
828+ :type select: :class:`list` of :class:`str` or None
829+
830+ :return: Combined list of one-to-many and many-to-many relationship
831+ metadata dictionaries.
832+ :rtype: :class:`list` of :class:`dict`
833+
834+ :raises ~PowerPlatform.Dataverse.core.errors.MetadataError:
835+ If the table is not found.
836+ :raises ~PowerPlatform.Dataverse.core.errors.HttpError:
837+ If the Web API request fails.
838+
839+ Example::
840+
841+ # List all relationships for the account table
842+ rels = client.tables.list_table_relationships("account")
843+ for rel in rels:
844+ print(f"{rel['SchemaName']} -> {rel.get('@odata.type')}")
845+ """
846+ with self ._client ._scoped_odata () as od :
847+ return od ._list_table_relationships (table , filter = filter , select = select )
0 commit comments