66from typing import Any , Dict , Optional , Union , List , Iterable , Iterator
77from contextlib import contextmanager
88
9+ import warnings
10+
911from azure .core .credentials import TokenCredential
1012
1113from .core ._auth import _AuthManager
1214from .core .config import DataverseConfig
1315from .data ._odata import _ODataClient
16+ from .operations .records import RecordOperations
17+ from .operations .query import QueryOperations
18+ from .operations .tables import TableOperations
1419
1520
1621class DataverseClient :
@@ -82,6 +87,11 @@ def __init__(
8287 self ._config = config or DataverseConfig .from_env ()
8388 self ._odata : Optional [_ODataClient ] = None
8489
90+ # Operation namespaces
91+ self .records = RecordOperations (self )
92+ self .query = QueryOperations (self )
93+ self .tables = TableOperations (self )
94+
8595 def _get_odata (self ) -> _ODataClient :
8696 """
8797 Get or create the internal OData client instance.
@@ -110,6 +120,9 @@ def _scoped_odata(self) -> Iterator[_ODataClient]:
110120 # ---------------- Unified CRUD: create/update/delete ----------------
111121 def create (self , table_schema_name : str , records : Union [Dict [str , Any ], List [Dict [str , Any ]]]) -> List [str ]:
112122 """
123+ .. deprecated::
124+ Use :meth:`client.records.create()` instead.
125+
113126 Create one or more records by table name.
114127
115128 :param table_schema_name: Schema name of the table (e.g. ``"account"``, ``"contact"``, or ``"new_MyTestTable"``).
@@ -140,25 +153,23 @@ def create(self, table_schema_name: str, records: Union[Dict[str, Any], List[Dic
140153 ids = client.create("account", records)
141154 print(f"Created {len(ids)} accounts")
142155 """
143- with self ._scoped_odata () as od :
144- entity_set = od ._entity_set_from_schema_name (table_schema_name )
145- if isinstance (records , dict ):
146- rid = od ._create (entity_set , table_schema_name , records )
147- # _create returns str on single input
148- if not isinstance (rid , str ):
149- raise TypeError ("_create (single) did not return GUID string" )
150- return [rid ]
151- if isinstance (records , list ):
152- ids = od ._create_multiple (entity_set , table_schema_name , records )
153- if not isinstance (ids , list ) or not all (isinstance (x , str ) for x in ids ):
154- raise TypeError ("_create (multi) did not return list[str]" )
155- return ids
156- raise TypeError ("records must be dict or list[dict]" )
156+ warnings .warn (
157+ "client.create() is deprecated. Use client.records.create() instead." ,
158+ DeprecationWarning , stacklevel = 2 ,
159+ )
160+ result = self .records .create (table_schema_name , records )
161+ # Old API always returned list[str], new returns str for single
162+ if isinstance (records , dict ):
163+ return [result ]
164+ return result
157165
158166 def update (
159167 self , table_schema_name : str , ids : Union [str , List [str ]], changes : Union [Dict [str , Any ], List [Dict [str , Any ]]]
160168 ) -> None :
161169 """
170+ .. deprecated::
171+ Use :meth:`client.records.update()` instead.
172+
162173 Update one or more records.
163174
164175 This method supports three usage patterns:
@@ -200,16 +211,11 @@ def update(
200211 ]
201212 client.update("account", ids, changes)
202213 """
203- with self ._scoped_odata () as od :
204- if isinstance (ids , str ):
205- if not isinstance (changes , dict ):
206- raise TypeError ("For single id, changes must be a dict" )
207- od ._update (table_schema_name , ids , changes ) # discard representation
208- return None
209- if not isinstance (ids , list ):
210- raise TypeError ("ids must be str or list[str]" )
211- od ._update_by_ids (table_schema_name , ids , changes )
212- return None
214+ warnings .warn (
215+ "client.update() is deprecated. Use client.records.update() instead." ,
216+ DeprecationWarning , stacklevel = 2 ,
217+ )
218+ self .records .update (table_schema_name , ids , changes )
213219
214220 def delete (
215221 self ,
@@ -218,6 +224,9 @@ def delete(
218224 use_bulk_delete : bool = True ,
219225 ) -> Optional [str ]:
220226 """
227+ .. deprecated::
228+ Use :meth:`client.records.delete()` instead.
229+
221230 Delete one or more records by GUID.
222231
223232 :param table_schema_name: Schema name of the table (e.g. ``"account"`` or ``"new_MyTestTable"``).
@@ -243,21 +252,11 @@ def delete(
243252
244253 job_id = client.delete("account", [id1, id2, id3])
245254 """
246- with self ._scoped_odata () as od :
247- if isinstance (ids , str ):
248- od ._delete (table_schema_name , ids )
249- return None
250- if not isinstance (ids , list ):
251- raise TypeError ("ids must be str or list[str]" )
252- if not ids :
253- return None
254- if not all (isinstance (rid , str ) for rid in ids ):
255- raise TypeError ("ids must contain string GUIDs" )
256- if use_bulk_delete :
257- return od ._delete_multiple (table_schema_name , ids )
258- for rid in ids :
259- od ._delete (table_schema_name , rid )
260- return None
255+ warnings .warn (
256+ "client.delete() is deprecated. Use client.records.delete() instead." ,
257+ DeprecationWarning , stacklevel = 2 ,
258+ )
259+ return self .records .delete (table_schema_name , ids , use_bulk_delete = use_bulk_delete )
261260
262261 def get (
263262 self ,
@@ -271,6 +270,9 @@ def get(
271270 page_size : Optional [int ] = None ,
272271 ) -> Union [Dict [str , Any ], Iterable [List [Dict [str , Any ]]]]:
273272 """
273+ .. deprecated::
274+ Use :meth:`client.records.get()` or :meth:`client.query.get()` instead.
275+
274276 Fetch a single record by ID or query multiple records.
275277
276278 When ``record_id`` is provided, returns a single record dictionary.
@@ -336,33 +338,24 @@ def get(
336338 ):
337339 print(f"Batch size: {len(batch)}")
338340 """
341+ warnings .warn (
342+ "client.get() is deprecated. Use client.records.get() or client.query.get() instead." ,
343+ DeprecationWarning , stacklevel = 2 ,
344+ )
339345 if record_id is not None :
340- if not isinstance (record_id , str ):
341- raise TypeError ("record_id must be str" )
342- with self ._scoped_odata () as od :
343- return od ._get (
344- table_schema_name ,
345- record_id ,
346- select = select ,
347- )
348-
349- def _paged () -> Iterable [List [Dict [str , Any ]]]:
350- with self ._scoped_odata () as od :
351- yield from od ._get_multiple (
352- table_schema_name ,
353- select = select ,
354- filter = filter ,
355- orderby = orderby ,
356- top = top ,
357- expand = expand ,
358- page_size = page_size ,
359- )
360-
361- return _paged ()
346+ return self .records .get (table_schema_name , record_id , select = select , expand = expand )
347+ else :
348+ return self .query .get (
349+ table_schema_name , select = select , filter = filter ,
350+ orderby = orderby , top = top , expand = expand , page_size = page_size ,
351+ )
362352
363353 # SQL via Web API sql parameter
364354 def query_sql (self , sql : str ):
365355 """
356+ .. deprecated::
357+ Use :meth:`client.query.sql()` instead.
358+
366359 Execute a read-only SQL query using the Dataverse Web API ``?sql`` capability.
367360
368361 The SQL query must follow the supported subset: a single SELECT statement with
@@ -394,12 +387,18 @@ def query_sql(self, sql: str):
394387 sql = "SELECT a.name, a.telephone1 FROM account AS a WHERE a.statecode = 0"
395388 results = client.query_sql(sql)
396389 """
397- with self ._scoped_odata () as od :
398- return od ._query_sql (sql )
390+ warnings .warn (
391+ "client.query_sql() is deprecated. Use client.query.sql() instead." ,
392+ DeprecationWarning , stacklevel = 2 ,
393+ )
394+ return self .query .sql (sql )
399395
400396 # Table metadata helpers
401397 def get_table_info (self , table_schema_name : str ) -> Optional [Dict [str , Any ]]:
402398 """
399+ .. deprecated::
400+ Use :meth:`client.tables.get()` instead.
401+
403402 Get basic metadata for a table if it exists.
404403
405404 :param table_schema_name: Schema name of the table (e.g. ``"new_MyTestTable"`` or ``"account"``).
@@ -418,8 +417,11 @@ def get_table_info(self, table_schema_name: str) -> Optional[Dict[str, Any]]:
418417 print(f"Logical name: {info['table_logical_name']}")
419418 print(f"Entity set: {info['entity_set_name']}")
420419 """
421- with self ._scoped_odata () as od :
422- return od ._get_table_info (table_schema_name )
420+ warnings .warn (
421+ "client.get_table_info() is deprecated. Use client.tables.get() instead." ,
422+ DeprecationWarning , stacklevel = 2 ,
423+ )
424+ return self .tables .get (table_schema_name )
423425
424426 def create_table (
425427 self ,
@@ -429,6 +431,9 @@ def create_table(
429431 primary_column_schema_name : Optional [str ] = None ,
430432 ) -> Dict [str , Any ]:
431433 """
434+ .. deprecated::
435+ Use :meth:`client.tables.create()` instead.
436+
432437 Create a simple custom table with specified columns.
433438
434439 :param table_schema_name: Schema name of the table with customization prefix value (e.g. ``"new_MyTestTable"``).
@@ -489,16 +494,21 @@ class ItemStatus(IntEnum):
489494 primary_column_schema_name="new_ProductName"
490495 )
491496 """
492- with self ._scoped_odata () as od :
493- return od ._create_table (
494- table_schema_name ,
495- columns ,
496- solution_unique_name ,
497- primary_column_schema_name ,
498- )
497+ warnings .warn (
498+ "client.create_table() is deprecated. Use client.tables.create() instead." ,
499+ DeprecationWarning , stacklevel = 2 ,
500+ )
501+ return self .tables .create (
502+ table_schema_name , columns ,
503+ solution = solution_unique_name ,
504+ primary_column = primary_column_schema_name ,
505+ )
499506
500507 def delete_table (self , table_schema_name : str ) -> None :
501508 """
509+ .. deprecated::
510+ Use :meth:`client.tables.delete()` instead.
511+
502512 Delete a custom table by name.
503513
504514 :param table_schema_name: Schema name of the table (e.g. ``"new_MyTestTable"`` or ``"account"``).
@@ -515,11 +525,17 @@ def delete_table(self, table_schema_name: str) -> None:
515525
516526 client.delete_table("new_MyTestTable")
517527 """
518- with self ._scoped_odata () as od :
519- od ._delete_table (table_schema_name )
528+ warnings .warn (
529+ "client.delete_table() is deprecated. Use client.tables.delete() instead." ,
530+ DeprecationWarning , stacklevel = 2 ,
531+ )
532+ self .tables .delete (table_schema_name )
520533
521534 def list_tables (self ) -> list [dict [str , Any ]]:
522535 """
536+ .. deprecated::
537+ Use :meth:`client.tables.list()` instead.
538+
523539 List all non-private tables in the Dataverse environment.
524540
525541 :return: List of EntityDefinition metadata dictionaries.
@@ -532,15 +548,21 @@ def list_tables(self) -> list[dict[str, Any]]:
532548 for table in tables:
533549 print(table["LogicalName"])
534550 """
535- with self ._scoped_odata () as od :
536- return od ._list_tables ()
551+ warnings .warn (
552+ "client.list_tables() is deprecated. Use client.tables.list() instead." ,
553+ DeprecationWarning , stacklevel = 2 ,
554+ )
555+ return self .tables .list ()
537556
538557 def create_columns (
539558 self ,
540559 table_schema_name : str ,
541560 columns : Dict [str , Any ],
542561 ) -> List [str ]:
543562 """
563+ .. deprecated::
564+ Use :meth:`client.tables.add_columns()` instead.
565+
544566 Create one or more columns on an existing table using a schema-style mapping.
545567
546568 :param table_schema_name: Schema name of the table (e.g. ``"new_MyTestTable"``).
@@ -564,18 +586,21 @@ def create_columns(
564586 )
565587 print(created) # ['new_Scratch', 'new_Flags', 'new_Document']
566588 """
567- with self . _scoped_odata () as od :
568- return od . _create_columns (
569- table_schema_name ,
570- columns ,
571- )
589+ warnings . warn (
590+ "client.create_columns() is deprecated. Use client.tables.add_columns() instead." ,
591+ DeprecationWarning , stacklevel = 2 ,
592+ )
593+ return self . tables . add_columns ( table_schema_name , columns )
572594
573595 def delete_columns (
574596 self ,
575597 table_schema_name : str ,
576598 columns : Union [str , List [str ]],
577599 ) -> List [str ]:
578600 """
601+ .. deprecated::
602+ Use :meth:`client.tables.remove_columns()` instead.
603+
579604 Delete one or more columns from a table.
580605
581606 :param table_schema_name: Schema name of the table (e.g. ``"new_MyTestTable"``).
@@ -593,11 +618,11 @@ def delete_columns(
593618 )
594619 print(removed) # ['new_Scratch', 'new_Flags']
595620 """
596- with self . _scoped_odata () as od :
597- return od . _delete_columns (
598- table_schema_name ,
599- columns ,
600- )
621+ warnings . warn (
622+ "client.delete_columns() is deprecated. Use client.tables.remove_columns() instead." ,
623+ DeprecationWarning , stacklevel = 2 ,
624+ )
625+ return self . tables . remove_columns ( table_schema_name , columns )
601626
602627 # File upload
603628 def upload_file (
@@ -699,4 +724,4 @@ def flush_cache(self, kind) -> int:
699724 return od ._flush_cache (kind )
700725
701726
702- __all__ = ["DataverseClient" ]
727+ __all__ = ["DataverseClient" , "RecordOperations" , "QueryOperations" , "TableOperations" ]
0 commit comments