Skip to content

Commit d7f9326

Browse files
committed
Use case-insenstivie prefixed logicalName in all operations
1 parent d07e52d commit d7f9326

6 files changed

Lines changed: 1005 additions & 193 deletions

File tree

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ Auth:
4141
| `delete` | `delete(logical_name, id)` | `None` | Delete one record. |
4242
| `delete` | `delete(logical_name, list[id], use_bulk_delete=True)` | `Optional[str]` | Delete many with async BulkDelete or sequential single-record delete. |
4343
| `query_sql` | `query_sql(sql)` | `list[dict]` | Constrained read-only SELECT via `?sql=`. |
44-
| `create_table` | `create_table(tablename, schema, solution_unique_name=None)` | `dict` | Creates custom table + columns. Friendly name (e.g. `SampleItem`) becomes schema `new_SampleItem`; explicit schema name (contains `_`) used as-is. Pass `solution_unique_name` to attach the table to a specific solution instead of the default solution. |
45-
| `create_column` | `create_column(tablename, columns)` | `list[str]` | Adds columns using a `{name: type}` mapping (same shape as `create_table` schema). Returns schema names for the created columns. |
44+
| `create_table` | `create_table(logical_name, schema, solution_unique_name=None)` | `dict` | Creates custom table + columns. Requires logical name with publisher prefix (e.g. `new_sampleitem`) and column names with same prefix (e.g. `{"new_code": "string"}`). Pass `solution_unique_name` to attach the table to a specific solution instead of the default solution. |
45+
| `create_column` | `create_column(tablename, columns)` | `list[str]` | Adds columns using a `{name: type}` mapping with publisher prefix (e.g. `{"new_category": "string"}`). Returns schema names for the created columns. |
4646
| `get_table_info` | `get_table_info(schema_name)` | `dict | None` | Basic table metadata by schema name (e.g. `new_SampleItem`). Friendly names not auto-converted. |
4747
| `list_tables` | `list_tables()` | `list[dict]` | Lists non-private tables. |
4848
| `delete_table` | `delete_table(tablename)` | `None` | Drops custom table. Accepts friendly or schema name; friendly converted to `new_<PascalCase>`. |
@@ -329,7 +329,7 @@ rec_id = client.create(logical, {name_attr: "Sample A"})[0]
329329

330330
# Clean up
331331
client.delete(logical, rec_id) # delete record
332-
client.delete_table("SampleItem") # delete table (friendly name or explicit schema new_SampleItem)
332+
client.delete_table("new_sampleitem") # delete table by logical name
333333
```
334334

335335
Notes:

examples/advanced/file_upload.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,8 @@ def ensure_table():
161161
if existing:
162162
print({"table": TABLE_SCHEMA_NAME, "existed": True})
163163
return existing
164-
log("client.create_table('new_FileSample', schema={title})")
165-
info = client.create_table(TABLE_SCHEMA_NAME, {"title": "string"})
164+
log("client.create_table('new_filesample', schema={new_title})")
165+
info = client.create_table(TABLE_SCHEMA_NAME, {"new_title": "string"})
166166
print({"table": TABLE_SCHEMA_NAME, "existed": False, "metadata_id": info.get('metadata_id')})
167167
return info
168168

examples/basic/quickstart.py

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,11 @@ class Status(IntEnum):
9595
# Check for existing table using list_tables
9696
log_call("client.list_tables()")
9797
tables = client.list_tables()
98-
existing_table = next((t for t in tables if t.get("SchemaName") == "new_SampleItem"), None)
98+
99+
# LogicalName should be lowercase, but let's be defensive with case-insensitive comparison
100+
existing_table = next((t for t in tables if t.get("LogicalName", "").lower() == "new_sampleitem"), None)
99101
if existing_table:
100-
table_info = client.get_table_info("new_SampleItem")
102+
table_info = client.get_table_info("new_sampleitem")
101103
created_this_run = False
102104
print({
103105
"table": table_info.get("entity_schema"),
@@ -106,20 +108,19 @@ class Status(IntEnum):
106108
"logical": table_info.get("entity_logical_name"),
107109
"metadata_id": table_info.get("metadata_id"),
108110
})
109-
110111
else:
111112
# Create it since it doesn't exist
112113
try:
113-
log_call("client.create_table('new_SampleItem', schema={code,count,amount,when,active,status<enum>})")
114+
log_call("client.create_table('new_sampleitem', schema={new_code,new_count,new_amount,new_when,new_active,new_status<enum>})")
114115
table_info = client.create_table(
115-
"new_SampleItem",
116+
"new_sampleitem",
116117
{
117-
"code": "string",
118-
"count": "int",
119-
"amount": "decimal",
120-
"when": "datetime",
121-
"active": "bool",
122-
"status": Status,
118+
"new_code": "string",
119+
"new_count": "int",
120+
"new_amount": "decimal",
121+
"new_when": "datetime",
122+
"new_active": "bool",
123+
"new_status": Status,
123124
},
124125
)
125126
created_this_run = True if table_info and table_info.get("columns_created") else False
@@ -146,11 +147,11 @@ class Status(IntEnum):
146147
pass
147148
# Fail fast: all operations must use the custom table
148149
sys.exit(1)
149-
entity_schema = table_info.get("entity_schema") or "new_SampleItem"
150-
logical = table_info.get("entity_logical_name")
150+
entity_schema = table_info.get("entity_schema") or "new_Sampleitem"
151+
logical = table_info.get("entity_logical_name") or "new_sampleitem"
151152
metadata_id = table_info.get("metadata_id")
152153
if not metadata_id:
153-
refreshed_info = client.get_table_info(entity_schema) or {}
154+
refreshed_info = client.get_table_info(logical) or {}
154155
metadata_id = refreshed_info.get("metadata_id")
155156
if metadata_id:
156157
table_info["metadata_id"] = metadata_id
@@ -553,8 +554,8 @@ def run_paging_demo(label: str, *, top: Optional[int], page_size: Optional[int])
553554
scratch_column = f"scratch_{int(time.time())}"
554555
column_payload = {scratch_column: "string"}
555556
try:
556-
log_call(f"client.create_column('{entity_schema}', {repr(column_payload)})")
557-
column_create = client.create_columns(entity_schema, column_payload)
557+
log_call(f"client.create_column('{logical}', {repr(column_payload)})")
558+
column_create = client.create_columns(logical, column_payload)
558559
if not isinstance(column_create, list) or not column_create:
559560
raise RuntimeError("create_column did not return schema list")
560561
created_details = column_create
@@ -589,10 +590,10 @@ def _metadata_after_create():
589590
attr_type_before = raw_type
590591
lowered = raw_type.lower()
591592
delete_target = attribute_schema or scratch_column
592-
log_call(f"client.delete_column('{entity_schema}', '{delete_target}')")
593+
log_call(f"client.delete_column('{logical}', '{delete_target}')")
593594

594595
def _delete_column():
595-
return client.delete_columns(entity_schema, delete_target)
596+
return client.delete_columns(logical, delete_target)
596597

597598
column_delete = backoff_retry(
598599
_delete_column,

src/dataverse_sdk/client.py

Lines changed: 45 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -372,13 +372,12 @@ def query_sql(self, sql: str):
372372
return self._get_odata()._query_sql(sql)
373373

374374
# Table metadata helpers
375-
def get_table_info(self, tablename: str) -> Optional[Dict[str, Any]]:
375+
def get_table_info(self, logical_name: str) -> Optional[Dict[str, Any]]:
376376
"""
377377
Get basic metadata for a custom table if it exists.
378-
379-
:param tablename: Table friendly name (e.g. ``"SampleItem"``) or full schema name
380-
(e.g. ``"new_SampleItem"``).
381-
:type tablename: str
378+
:param logical_name: Table logical name with publisher prefix (e.g. ``"new_sampleitem"``).
379+
Lookup is case-insensitive (e.g., ``"new_SampleItem"`` will also work).
380+
:type logical_name: str
382381
383382
:return: Dictionary containing table metadata with keys ``entity_schema``,
384383
``entity_logical_name``, ``entity_set_name``, and ``metadata_id``.
@@ -388,28 +387,25 @@ def get_table_info(self, tablename: str) -> Optional[Dict[str, Any]]:
388387
Example:
389388
Retrieve table metadata::
390389
391-
info = client.get_table_info("SampleItem")
392-
if info:
390+
info = client.get_table_info("new_sampleitem") if info:
393391
print(f"Logical name: {info['entity_logical_name']}")
394392
print(f"Entity set: {info['entity_set_name']}")
395393
"""
396-
return self._get_odata()._get_table_info(tablename)
394+
return self._get_odata()._get_table_info(logical_name)
397395

398396
def create_table(
399397
self,
400-
tablename: str,
398+
logical_name: str,
401399
schema: Dict[str, Any],
402400
solution_unique_name: Optional[str] = None,
403401
) -> Dict[str, Any]:
404402
"""
405403
Create a simple custom table with specified columns.
406404
407-
:param tablename: Table friendly name (e.g. ``"SampleItem"``) or full schema name
408-
(e.g. ``"new_SampleItem"``). If a publisher prefix is not included, the default
409-
publisher prefix will be applied.
410-
:type tablename: str
411-
:param schema: Dictionary mapping column logical names (without prefix) to their types.
412-
Supported types:
405+
:param logical_name: Table logical name with publisher prefix (e.g. ``"new_orders"``).
406+
Both table and column names must include the publisher prefix (default is ``"new_"``).
407+
:type logical_name: str
408+
:param schema: Dictionary mapping column logical names (with prefix) to their types.
413409
414410
- Primitive types: ``"string"``, ``"int"``, ``"decimal"``, ``"float"``, ``"datetime"``, ``"bool"``
415411
- Enum subclass (IntEnum preferred): Creates a local option set. Optional multilingual
@@ -432,10 +428,11 @@ class ItemStatus(IntEnum):
432428
``entity_set_name``, ``entity_logical_name``, ``metadata_id``, and ``columns_created``.
433429
:rtype: dict
434430
435-
:raises ~dataverse_sdk.errors.MetadataError: If table creation fails or the schema is invalid.
431+
:raises ~dataverse_sdk.errors.HttpError: If server rejects the metadata (invalid names, missing prefix, etc.).
432+
:raises ~dataverse_sdk.errors.MetadataError: If table creation fails.
436433
437434
Example:
438-
Create a table with simple columns::
435+
Create a table with simple columns (using default publisher prefix ``new_``)::
439436
440437
from enum import IntEnum
441438
@@ -444,30 +441,27 @@ class ItemStatus(IntEnum):
444441
INACTIVE = 2
445442
446443
schema = {
447-
"title": "string",
448-
"quantity": "int",
449-
"price": "decimal",
450-
"available": "bool",
451-
"status": ItemStatus
444+
"new_title": "string",
445+
"new_quantity": "int",
446+
"new_price": "decimal",
447+
"new_available": "bool",
448+
"new_status": ItemStatus
452449
}
453-
454-
result = client.create_table("SampleItem", schema)
450+
result = client.create_table("new_sampleitem", schema)
455451
print(f"Created table: {result['entity_logical_name']}")
456452
print(f"Columns: {result['columns_created']}")
457453
"""
458454
return self._get_odata()._create_table(
459-
tablename,
455+
logical_name,
460456
schema,
461457
solution_unique_name,
462458
)
463459

464-
def delete_table(self, tablename: str) -> None:
460+
def delete_table(self, logical_name: str) -> None:
465461
"""
466-
Delete a custom table by name.
467-
468-
:param tablename: Table friendly name (e.g. ``"SampleItem"``) or full schema name
469-
(e.g. ``"new_SampleItem"``).
470-
:type tablename: str
462+
Delete a custom table by logical name.
463+
:param logical_name: Table logical name with publisher prefix (e.g. ``"new_sampleitem"``).
464+
:type logical_name: str
471465
472466
:raises ~dataverse_sdk.errors.MetadataError: If the table does not exist or deletion fails.
473467
@@ -478,9 +472,9 @@ def delete_table(self, tablename: str) -> None:
478472
Example:
479473
Delete a custom table::
480474
481-
client.delete_table("SampleItem")
475+
client.delete_table("new_sampleitem")
482476
"""
483-
self._get_odata()._delete_table(tablename)
477+
self._get_odata()._delete_table(logical_name)
484478

485479
def list_tables(self) -> list[str]:
486480
"""
@@ -500,63 +494,59 @@ def list_tables(self) -> list[str]:
500494

501495
def create_columns(
502496
self,
503-
tablename: str,
497+
logical_name: str,
504498
columns: Dict[str, Any],
505499
) -> List[str]:
506500
"""
507501
Create one or more columns on an existing table using a schema-style mapping.
508502
509-
:param tablename: Friendly name ("SampleItem") or full schema name ("new_SampleItem").
510-
:type tablename: str
511-
:param columns: Mapping of logical names (without prefix) to supported types. Primitive types include
503+
:param logical_name: Table logical name with publisher prefix (e.g. ``"new_sampleitem"``).
504+
:type logical_name: str
505+
:param columns: Mapping of column names with publisher prefix to supported types. Primitive types include
512506
``string``, ``int``, ``decimal``, ``float``, ``datetime``, and ``bool``. Enum subclasses (IntEnum preferred)
513507
generate a local option set and can specify localized labels via ``__labels__``.
514508
:type columns: Dict[str, Any]
515-
:returns: Schema names for the columns that were created.
509+
:returns: Logical names for the columns that were created.
516510
:rtype: list[str]
517511
Example:
518512
Create two columns on the custom table::
519-
520513
created = client.create_columns(
521-
"new_SampleItem",
514+
"new_sampleitem",
522515
{
523-
"scratch": "string",
524-
"flags": "bool",
516+
"new_scratch": "string",
517+
"new_flags": "bool",
525518
},
526519
)
527520
print(created)
528521
"""
529522
return self._get_odata()._create_columns(
530-
tablename,
523+
logical_name,
531524
columns,
532525
)
533526

534527
def delete_columns(
535528
self,
536-
tablename: str,
529+
logical_name: str,
537530
columns: Union[str, List[str]],
538531
) -> List[str]:
539532
"""
540533
Delete one or more columns from a table.
541-
542-
:param tablename: Friendly or schema name of the table.
543-
:type tablename: str
544-
:param columns: Column name or list of column names to remove. Friendly names are normalized to schema
545-
names using the same prefix logic as ``create_columns``.
534+
:param logical_name: Table logical name with publisher prefix (e.g. ``"new_sampleitem"``).
535+
:type logical_name: str
536+
:param columns: Column name or list of column names to remove with publisher prefix (e.g. ``"new_scratch"``).
546537
:type columns: str | list[str]
547-
:returns: Schema names for the columns that were removed.
538+
:returns: Logical names for the columns that were removed.
548539
:rtype: list[str]
549540
Example:
550-
Remove two custom columns by schema name:
551-
541+
Remove two custom columns:
552542
removed = client.delete_columns(
553-
"new_SampleItem",
554-
["new_Scratch", "new_Flags"],
543+
"new_sampleitem",
544+
["new_scratch", "new_flags"],
555545
)
556546
print(removed)
557547
"""
558548
return self._get_odata()._delete_columns(
559-
tablename,
549+
logical_name,
560550
columns,
561551
)
562552

0 commit comments

Comments
 (0)