Skip to content

7.2.0 πŸ¦β€β¬›

Choose a tag to compare

@poissoncorp poissoncorp released this 06 Mar 11:10
· 45 commits to v7.2 since this release
0cfd03a

7.2.0 syncs the Python client with RavenDB 7.2 C# client. The two headline features are Remote Attachments (offloading attachment bytes to S3 or Azure Blob Storage) and JSON Schema Validation (enforcing document structure).

Docs:

Technical Guides:

Highlights

Remote Attachments

Attachments can now be pushed to a remote cloud storage automatically thanks to RavenDB new feature - Remote Attachments.
Configure one or more named destinations (S3 or Azure Blob), then schedule attachments for upload.
The server's background sender picks them up and pushes the bytes to the cloud at or after the scheduled time.

from ravendb.documents.operations.attachments import (
    ConfigureRemoteAttachmentsOperation,
    RemoteAttachmentsConfiguration,
    RemoteAttachmentsDestinationConfiguration,
    RemoteAttachmentsS3Settings,
    RemoteAttachmentParameters,
    StoreAttachmentParameters,
)
import datetime

# 1. Configure a destination (once per database)
store.maintenance.send(ConfigureRemoteAttachmentsOperation(
    RemoteAttachmentsConfiguration(
        destinations={
            "s3-archive": RemoteAttachmentsDestinationConfiguration(
                s3_settings=RemoteAttachmentsS3Settings(
                    aws_access_key="AKIAIOSFODNN7EXAMPLE",
                    aws_secret_key="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
                    aws_region_name="us-east-1",
                    bucket_name="my-ravendb-attachments",
                )
            )
        }
    )
))

# 2. Attach a file scheduled for cloud upload
at = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(minutes=5)
with store.open_session() as session:
    params = StoreAttachmentParameters("invoice.pdf", pdf_bytes, content_type="application/pdf")
    params.remote_parameters = RemoteAttachmentParameters(identifier="s3-archive", at=at)
    session.advanced.attachments.store_with_parameters("orders/1", params)
    session.save_changes()

Bulk insert remote attachments support

import datetime
from ravendb.documents.operations.attachments import RemoteAttachmentParameters, StoreAttachmentParameters

at = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(minutes=5)

with store.bulk_insert() as bulk_insert:
    for i in range(1000):
        doc_id = f"orders/{i}"
        bulk_insert.store_as({"name": f"Order {i}"}, doc_id)

        attachments = bulk_insert.attachments_for(doc_id)

        params = StoreAttachmentParameters("invoice.pdf", pdf_bytes, content_type="application/pdf")
        params.remote_parameters = RemoteAttachmentParameters(identifier="s3-archive", at=at)
        attachments.store_with_parameters(params)

New operations: ConfigureRemoteAttachmentsOperation, GetRemoteAttachmentsConfigurationOperation
New classes: RemoteAttachmentsConfiguration, RemoteAttachmentsS3Settings, RemoteAttachmentsAzureSettings, RemoteAttachmentsDestinationConfiguration, RemoteAttachmentParameters, StoreAttachmentParameters, RemoteAttachmentFlags
Updated: PutAttachmentOperation, GetAttachmentOperation, session store_with_parameters, bulk insert attachment support

Bulk-Delete Attachments Operation

Delete multiple attachments in a single HTTP request:

from ravendb.documents.operations.attachments import AttachmentRequest, DeleteAttachmentsOperation

store.operations.send(DeleteAttachmentsOperation([
    AttachmentRequest("orders/1", "invoice.pdf"),
    AttachmentRequest("orders/2", "photo.jpg"),
]))

JSON Schema Validation

Enforce a JSON Schema on a collection at write time. Invalid documents are rejected with SchemaValidationException. Existing documents can be audited without blocking writes using StartSchemaValidationOperation.

import json
from ravendb.documents.operations.schema_validation import (
    ConfigureSchemaValidationOperation,
    SchemaDefinition,
    SchemaValidationConfiguration,
    StartSchemaValidationOperation,
    ValidateSchemaResult,
)
from ravendb.exceptions.raven_exceptions import SchemaValidationException

schema = json.dumps({
    "type": "object",
    "properties": {"name": {"type": "string"}, "age": {"type": "integer"}},
    "required": ["name", "age"],
})

# Enforce schema on writes
store.maintenance.send(ConfigureSchemaValidationOperation(
    SchemaValidationConfiguration(
        validators_per_collection={"Users": SchemaDefinition(schema=schema)}
    )
))

# Invalid document is rejected immediately at save_changes()
try:
    with store.open_session() as session:
        session.store({"age": "not-a-number"}, "users/bad")  # missing name, wrong age type
        session.save_changes()
except SchemaValidationException as e:
    print("Rejected:", e)

# Audit existing documents (non-blocking)
params = StartSchemaValidationOperation.Parameters(schema_definition=schema, collection="Users")
op = store.maintenance.send_async(StartSchemaValidationOperation(params))
op.wait_for_completion()
result = op.fetch_operations_status()["Result"]
print(f"Scanned: {result['ValidatedCount']}, Errors: {result['ErrorCount']}")

New module: ravendb.documents.operations.schema_validation
New exception: SchemaValidationException

Schema validation inside an index definition

A schema can also be embedded directly in an IndexDefinition via schema_definitions. During indexing the map calls Schema.GetErrorsFor(doc) to project per-document validation errors into a stored field β€” without blocking writes.

import json
from ravendb.documents.indexes.definitions import FieldStorage, IndexDefinition, IndexFieldOptions
from ravendb.documents.operations.indexes import PutIndexesOperation

schema = json.dumps({
    "properties": {"age": {"minimum": 0, "maximum": 150}},
    "required": ["name", "age"],
})

index_def = IndexDefinition(
    name="Users/WithSchemaErrors",
    maps={"""
        from doc in docs.Users
        select new { doc.name, Errors = Schema.GetErrorsFor(doc) }
    """},
    fields={"Errors": IndexFieldOptions(storage=FieldStorage.YES)},
    schema_definitions={"Users": schema},  # collection β†’ JSON Schema string
)
store.maintenance.send(PutIndexesOperation(index_def))

# Query and inspect per-document errors
with store.open_session() as session:
    results = list(
        session.query_index("Users/WithSchemaErrors", dict)
               .select_fields(dict, "name", "Errors")
    )
    for r in results:
        if r.get("Errors"):
            print(r["name"], "β†’", r["Errors"])

Other Changes

  • IndexDefinition: new schema_definitions field (Dict[str, str]) linking index fields to schema names
  • DetailedDatabaseStatistics: new count_of_remote_attachments field
  • DatabaseRecord: new schema_validation and remote_attachments fields
  • Exception dispatcher: now properly wired for all non-2xx and conflict responses

PyPi link: https://pypi.org/project/ravendb/7.2.0/

PRs

Full Changelog: 7.1.5...7.2.0