Skip to content
62 changes: 49 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,12 @@ The SDK provides a simple, pythonic interface for Dataverse operations:
| Concept | Description |
|---------|-------------|
| **DataverseClient** | Main entry point for all operations with environment connection |
| **Records** | Dataverse records represented as Python dictionaries with logical field names |
| **Logical Names** | Use table logical names (`"account"`) and column logical names (`"name"`) |
| **Records** | Dataverse records represented as Python dictionaries with column schema names |
| **Schema names** | Use table schema names (`"account"`, `"new_MyTestTable"`) and column schema names (`"name"`, `"new_MyTestColumn"`). See: [Table definitions in Microsoft Dataverse](https://learn.microsoft.com/en-us/power-apps/developer/data-platform/entity-metadata) |
| **Bulk Operations** | Efficient bulk processing for multiple records with automatic optimization |
| **Paging** | Automatic handling of large result sets with iterators |
| **Structured Errors** | Detailed exception hierarchy with retry guidance and diagnostic information |
| **Customization prefix values** | Custom tables and columns require a customization prefix value to be included for all operations (e.g., `"new_MyTestTable"`, not `"MyTestTable"`). See: [Table definitions in Microsoft Dataverse](https://learn.microsoft.com/en-us/power-apps/developer/data-platform/entity-metadata) |

## Examples

Expand Down Expand Up @@ -175,40 +176,75 @@ for record in results:
print(record["name"])

# OData query with paging
# Note: filter and expand parameters are case sensitive
pages = client.get(
"account",
select=["accountid", "name"],
filter="statecode eq 0",
select=["accountid", "name"], # select is case-insensitive (automatically lowercased)
filter="statecode eq 0", # filter must use lowercase logical names (not transformed)
top=100
)
for page in pages:
for record in page:
print(record["name"])

# Query with navigation property expansion (case-sensitive!)
pages = client.get(
"account",
select=["name"],
expand=["primarycontactid"], # Navigation property names are case-sensitive
filter="statecode eq 0" # Column names must be lowercase logical names
)
for page in pages:
for account in page:
contact = account.get("primarycontactid", {})
print(f"{account['name']} - Contact: {contact.get('fullname', 'N/A')}")
```

> **Important**: When using `filter` and `expand` parameters:
> - **`filter`**: Column names must use exact lowercase logical names (e.g., `"statecode eq 0"`, not `"StateCode eq 0"`)
> - **`expand`**: Navigation property names are case-sensitive and must match the exact server names
> - **`select`** and **`orderby`**: Case-insensitive; automatically converted to lowercase

### Table management

```python
# Create a custom table
table_info = client.create_table("Product", {
"code": "string",
"price": "decimal",
"active": "bool"
# Create a custom table, including the customization prefix value in the schema names for the table and columns.
table_info = client.create_table("new_Product", {
"new_Code": "string",
"new_Price": "decimal",
"new_Active": "bool"
})

# Add columns to existing table
client.create_columns("Product", {"category": "string"})
# Create with custom primary column name and solution assignment
table_info = client.create_table(
table_schema_name="new_Product",
columns={
"new_Code": "string",
"new_Price": "decimal"
},
solution_unique_name="MyPublisher", # Optional: add to specific solution
primary_column_schema_name="new_ProductName" # Optional: custom primary column (default is "{customization prefix value}_Name")
)

# Add columns to existing table (columns must include customization prefix value)
client.create_columns("new_Product", {"new_Category": "string"})

# Remove columns
client.delete_columns("new_Product", ["new_Category"])

# Clean up
client.delete_table("Product")
client.delete_table("new_Product")
```

> **Important**: All custom column names must include the customization prefix value (e.g., `"new_"`).
> This ensures explicit, predictable naming and aligns with Dataverse metadata requirements.

### File operations

```python
# Upload a file to a record
client.upload_file(
logical_name="account",
table_schema_name="account",
record_id=account_id,
file_name_attribute="new_document",
path="/path/to/document.pdf"
Expand Down
Loading
Loading