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,24 @@ 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 ,
159+ stacklevel = 2 ,
160+ )
161+ result = self .records .create (table_schema_name , records )
162+ # Old API always returned list[str], new returns str for single
163+ if isinstance (records , dict ):
164+ return [result ]
165+ return result
157166
158167 def update (
159168 self , table_schema_name : str , ids : Union [str , List [str ]], changes : Union [Dict [str , Any ], List [Dict [str , Any ]]]
160169 ) -> None :
161170 """
171+ .. deprecated::
172+ Use :meth:`client.records.update()` instead.
173+
162174 Update one or more records.
163175
164176 This method supports three usage patterns:
@@ -200,16 +212,12 @@ def update(
200212 ]
201213 client.update("account", ids, changes)
202214 """
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
215+ warnings .warn (
216+ "client.update() is deprecated. Use client.records.update() instead." ,
217+ DeprecationWarning ,
218+ stacklevel = 2 ,
219+ )
220+ self .records .update (table_schema_name , ids , changes )
213221
214222 def delete (
215223 self ,
@@ -218,6 +226,9 @@ def delete(
218226 use_bulk_delete : bool = True ,
219227 ) -> Optional [str ]:
220228 """
229+ .. deprecated::
230+ Use :meth:`client.records.delete()` instead.
231+
221232 Delete one or more records by GUID.
222233
223234 :param table_schema_name: Schema name of the table (e.g. ``"account"`` or ``"new_MyTestTable"``).
@@ -243,21 +254,12 @@ def delete(
243254
244255 job_id = client.delete("account", [id1, id2, id3])
245256 """
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
257+ warnings .warn (
258+ "client.delete() is deprecated. Use client.records.delete() instead." ,
259+ DeprecationWarning ,
260+ stacklevel = 2 ,
261+ )
262+ return self .records .delete (table_schema_name , ids , use_bulk_delete = use_bulk_delete )
261263
262264 def get (
263265 self ,
@@ -271,6 +273,9 @@ def get(
271273 page_size : Optional [int ] = None ,
272274 ) -> Union [Dict [str , Any ], Iterable [List [Dict [str , Any ]]]]:
273275 """
276+ .. deprecated::
277+ Use :meth:`client.records.get()` or :meth:`client.query.get()` instead.
278+
274279 Fetch a single record by ID or query multiple records.
275280
276281 When ``record_id`` is provided, returns a single record dictionary.
@@ -336,33 +341,30 @@ def get(
336341 ):
337342 print(f"Batch size: {len(batch)}")
338343 """
344+ warnings .warn (
345+ "client.get() is deprecated. Use client.records.get() or client.query.get() instead." ,
346+ DeprecationWarning ,
347+ stacklevel = 2 ,
348+ )
339349 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 ()
350+ return self .records .get (table_schema_name , record_id , select = select , expand = expand )
351+ else :
352+ return self .query .get (
353+ table_schema_name ,
354+ select = select ,
355+ filter = filter ,
356+ orderby = orderby ,
357+ top = top ,
358+ expand = expand ,
359+ page_size = page_size ,
360+ )
362361
363362 # SQL via Web API sql parameter
364363 def query_sql (self , sql : str ):
365364 """
365+ .. deprecated::
366+ Use :meth:`client.query.sql()` instead.
367+
366368 Execute a read-only SQL query using the Dataverse Web API ``?sql`` capability.
367369
368370 The SQL query must follow the supported subset: a single SELECT statement with
@@ -394,12 +396,19 @@ def query_sql(self, sql: str):
394396 sql = "SELECT a.name, a.telephone1 FROM account AS a WHERE a.statecode = 0"
395397 results = client.query_sql(sql)
396398 """
397- with self ._scoped_odata () as od :
398- return od ._query_sql (sql )
399+ warnings .warn (
400+ "client.query_sql() is deprecated. Use client.query.sql() instead." ,
401+ DeprecationWarning ,
402+ stacklevel = 2 ,
403+ )
404+ return self .query .sql (sql )
399405
400406 # Table metadata helpers
401407 def get_table_info (self , table_schema_name : str ) -> Optional [Dict [str , Any ]]:
402408 """
409+ .. deprecated::
410+ Use :meth:`client.tables.get()` instead.
411+
403412 Get basic metadata for a table if it exists.
404413
405414 :param table_schema_name: Schema name of the table (e.g. ``"new_MyTestTable"`` or ``"account"``).
@@ -418,8 +427,12 @@ def get_table_info(self, table_schema_name: str) -> Optional[Dict[str, Any]]:
418427 print(f"Logical name: {info['table_logical_name']}")
419428 print(f"Entity set: {info['entity_set_name']}")
420429 """
421- with self ._scoped_odata () as od :
422- return od ._get_table_info (table_schema_name )
430+ warnings .warn (
431+ "client.get_table_info() is deprecated. Use client.tables.get() instead." ,
432+ DeprecationWarning ,
433+ stacklevel = 2 ,
434+ )
435+ return self .tables .get (table_schema_name )
423436
424437 def create_table (
425438 self ,
@@ -429,6 +442,9 @@ def create_table(
429442 primary_column_schema_name : Optional [str ] = None ,
430443 ) -> Dict [str , Any ]:
431444 """
445+ .. deprecated::
446+ Use :meth:`client.tables.create()` instead.
447+
432448 Create a simple custom table with specified columns.
433449
434450 :param table_schema_name: Schema name of the table with customization prefix value (e.g. ``"new_MyTestTable"``).
@@ -489,16 +505,23 @@ class ItemStatus(IntEnum):
489505 primary_column_schema_name="new_ProductName"
490506 )
491507 """
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- )
508+ warnings .warn (
509+ "client.create_table() is deprecated. Use client.tables.create() instead." ,
510+ DeprecationWarning ,
511+ stacklevel = 2 ,
512+ )
513+ return self .tables .create (
514+ table_schema_name ,
515+ columns ,
516+ solution = solution_unique_name ,
517+ primary_column = primary_column_schema_name ,
518+ )
499519
500520 def delete_table (self , table_schema_name : str ) -> None :
501521 """
522+ .. deprecated::
523+ Use :meth:`client.tables.delete()` instead.
524+
502525 Delete a custom table by name.
503526
504527 :param table_schema_name: Schema name of the table (e.g. ``"new_MyTestTable"`` or ``"account"``).
@@ -515,11 +538,18 @@ def delete_table(self, table_schema_name: str) -> None:
515538
516539 client.delete_table("new_MyTestTable")
517540 """
518- with self ._scoped_odata () as od :
519- od ._delete_table (table_schema_name )
541+ warnings .warn (
542+ "client.delete_table() is deprecated. Use client.tables.delete() instead." ,
543+ DeprecationWarning ,
544+ stacklevel = 2 ,
545+ )
546+ self .tables .delete (table_schema_name )
520547
521548 def list_tables (self ) -> list [dict [str , Any ]]:
522549 """
550+ .. deprecated::
551+ Use :meth:`client.tables.list()` instead.
552+
523553 List all non-private tables in the Dataverse environment.
524554
525555 :return: List of EntityDefinition metadata dictionaries.
@@ -532,15 +562,22 @@ def list_tables(self) -> list[dict[str, Any]]:
532562 for table in tables:
533563 print(table["LogicalName"])
534564 """
535- with self ._scoped_odata () as od :
536- return od ._list_tables ()
565+ warnings .warn (
566+ "client.list_tables() is deprecated. Use client.tables.list() instead." ,
567+ DeprecationWarning ,
568+ stacklevel = 2 ,
569+ )
570+ return self .tables .list ()
537571
538572 def create_columns (
539573 self ,
540574 table_schema_name : str ,
541575 columns : Dict [str , Any ],
542576 ) -> List [str ]:
543577 """
578+ .. deprecated::
579+ Use :meth:`client.tables.add_columns()` instead.
580+
544581 Create one or more columns on an existing table using a schema-style mapping.
545582
546583 :param table_schema_name: Schema name of the table (e.g. ``"new_MyTestTable"``).
@@ -564,18 +601,22 @@ def create_columns(
564601 )
565602 print(created) # ['new_Scratch', 'new_Flags', 'new_Document']
566603 """
567- with self ._scoped_odata () as od :
568- return od ._create_columns (
569- table_schema_name ,
570- columns ,
571- )
604+ warnings .warn (
605+ "client.create_columns() is deprecated. Use client.tables.add_columns() instead." ,
606+ DeprecationWarning ,
607+ stacklevel = 2 ,
608+ )
609+ return self .tables .add_columns (table_schema_name , columns )
572610
573611 def delete_columns (
574612 self ,
575613 table_schema_name : str ,
576614 columns : Union [str , List [str ]],
577615 ) -> List [str ]:
578616 """
617+ .. deprecated::
618+ Use :meth:`client.tables.remove_columns()` instead.
619+
579620 Delete one or more columns from a table.
580621
581622 :param table_schema_name: Schema name of the table (e.g. ``"new_MyTestTable"``).
@@ -593,11 +634,12 @@ def delete_columns(
593634 )
594635 print(removed) # ['new_Scratch', 'new_Flags']
595636 """
596- with self ._scoped_odata () as od :
597- return od ._delete_columns (
598- table_schema_name ,
599- columns ,
600- )
637+ warnings .warn (
638+ "client.delete_columns() is deprecated. Use client.tables.remove_columns() instead." ,
639+ DeprecationWarning ,
640+ stacklevel = 2 ,
641+ )
642+ return self .tables .remove_columns (table_schema_name , columns )
601643
602644 # File upload
603645 def upload_file (
0 commit comments