lumera 0.8.3__tar.gz → 0.9.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {lumera-0.8.3 → lumera-0.9.1}/PKG-INFO +1 -1
- {lumera-0.8.3 → lumera-0.9.1}/lumera/pb.py +73 -17
- {lumera-0.8.3 → lumera-0.9.1}/lumera/sdk.py +33 -13
- {lumera-0.8.3 → lumera-0.9.1}/lumera.egg-info/PKG-INFO +1 -1
- {lumera-0.8.3 → lumera-0.9.1}/pyproject.toml +1 -1
- {lumera-0.8.3 → lumera-0.9.1}/tests/test_sdk.py +42 -0
- {lumera-0.8.3 → lumera-0.9.1}/lumera/__init__.py +0 -0
- {lumera-0.8.3 → lumera-0.9.1}/lumera/_utils.py +0 -0
- {lumera-0.8.3 → lumera-0.9.1}/lumera/automations.py +0 -0
- {lumera-0.8.3 → lumera-0.9.1}/lumera/exceptions.py +0 -0
- {lumera-0.8.3 → lumera-0.9.1}/lumera/google.py +0 -0
- {lumera-0.8.3 → lumera-0.9.1}/lumera/llm.py +0 -0
- {lumera-0.8.3 → lumera-0.9.1}/lumera/locks.py +0 -0
- {lumera-0.8.3 → lumera-0.9.1}/lumera/storage.py +0 -0
- {lumera-0.8.3 → lumera-0.9.1}/lumera/webhooks.py +0 -0
- {lumera-0.8.3 → lumera-0.9.1}/lumera.egg-info/SOURCES.txt +0 -0
- {lumera-0.8.3 → lumera-0.9.1}/lumera.egg-info/dependency_links.txt +0 -0
- {lumera-0.8.3 → lumera-0.9.1}/lumera.egg-info/requires.txt +0 -0
- {lumera-0.8.3 → lumera-0.9.1}/lumera.egg-info/top_level.txt +0 -0
- {lumera-0.8.3 → lumera-0.9.1}/setup.cfg +0 -0
|
@@ -318,51 +318,84 @@ def delete(collection: str, record_id: str) -> None:
|
|
|
318
318
|
# =============================================================================
|
|
319
319
|
|
|
320
320
|
|
|
321
|
-
def bulk_delete(
|
|
321
|
+
def bulk_delete(
|
|
322
|
+
collection: str,
|
|
323
|
+
record_ids: Sequence[str],
|
|
324
|
+
*,
|
|
325
|
+
transaction: bool = False,
|
|
326
|
+
) -> dict[str, Any]:
|
|
322
327
|
"""Delete multiple records by ID.
|
|
323
328
|
|
|
324
329
|
Args:
|
|
325
330
|
collection: Collection name or ID
|
|
326
331
|
record_ids: List of record IDs to delete (max 1000)
|
|
332
|
+
transaction: If True, use all-or-nothing semantics (rollback on any failure).
|
|
333
|
+
If False (default), partial success is allowed.
|
|
327
334
|
|
|
328
335
|
Returns:
|
|
329
336
|
Result with succeeded/failed counts and any errors:
|
|
330
337
|
{
|
|
331
338
|
"succeeded": 10,
|
|
332
339
|
"failed": 0,
|
|
333
|
-
"errors": []
|
|
340
|
+
"errors": [],
|
|
341
|
+
"rolled_back": false # only present if transaction=True and failed
|
|
334
342
|
}
|
|
335
343
|
|
|
336
344
|
Example:
|
|
337
345
|
>>> result = pb.bulk_delete("deposits", ["id1", "id2", "id3"])
|
|
338
346
|
>>> print(f"Deleted {result['succeeded']} records")
|
|
347
|
+
|
|
348
|
+
>>> # Use transaction mode for all-or-nothing
|
|
349
|
+
>>> result = pb.bulk_delete("deposits", ids, transaction=True)
|
|
339
350
|
"""
|
|
340
|
-
return _bulk_delete_records(collection, record_ids)
|
|
351
|
+
return _bulk_delete_records(collection, record_ids, transaction=transaction)
|
|
341
352
|
|
|
342
353
|
|
|
343
354
|
def bulk_update(
|
|
344
355
|
collection: str,
|
|
345
|
-
|
|
346
|
-
|
|
356
|
+
records: Sequence[dict[str, Any]],
|
|
357
|
+
*,
|
|
358
|
+
transaction: bool = False,
|
|
347
359
|
) -> dict[str, Any]:
|
|
348
|
-
"""Update multiple records with
|
|
360
|
+
"""Update multiple records with individual data per record.
|
|
361
|
+
|
|
362
|
+
Each record must have an 'id' field plus fields to update.
|
|
363
|
+
Records must exist (returns error if not found, does not create).
|
|
349
364
|
|
|
350
365
|
Args:
|
|
351
366
|
collection: Collection name or ID
|
|
352
|
-
|
|
353
|
-
|
|
367
|
+
records: List of records to update (max 1000). Each must have 'id' field.
|
|
368
|
+
transaction: If True, use all-or-nothing semantics (rollback on any failure).
|
|
369
|
+
If False (default), partial success is allowed.
|
|
354
370
|
|
|
355
371
|
Returns:
|
|
356
|
-
Result with succeeded/failed counts
|
|
372
|
+
Result with succeeded/failed counts:
|
|
373
|
+
{
|
|
374
|
+
"succeeded": 2,
|
|
375
|
+
"failed": 0,
|
|
376
|
+
"errors": [],
|
|
377
|
+
"rolled_back": false # only present if transaction=True and failed
|
|
378
|
+
}
|
|
357
379
|
|
|
358
380
|
Example:
|
|
359
|
-
>>> result = pb.bulk_update("deposits", [
|
|
381
|
+
>>> result = pb.bulk_update("deposits", [
|
|
382
|
+
... {"id": "rec1", "status": "approved", "amount": 100},
|
|
383
|
+
... {"id": "rec2", "status": "rejected", "amount": 200},
|
|
384
|
+
... ])
|
|
360
385
|
>>> print(f"Updated {result['succeeded']} records")
|
|
386
|
+
|
|
387
|
+
>>> # Use transaction mode for all-or-nothing
|
|
388
|
+
>>> result = pb.bulk_update("deposits", records, transaction=True)
|
|
361
389
|
"""
|
|
362
|
-
return _bulk_update_records(collection,
|
|
390
|
+
return _bulk_update_records(collection, records, transaction=transaction)
|
|
363
391
|
|
|
364
392
|
|
|
365
|
-
def bulk_upsert(
|
|
393
|
+
def bulk_upsert(
|
|
394
|
+
collection: str,
|
|
395
|
+
records: Sequence[dict[str, Any]],
|
|
396
|
+
*,
|
|
397
|
+
transaction: bool = False,
|
|
398
|
+
) -> dict[str, Any]:
|
|
366
399
|
"""Create or update multiple records by ID.
|
|
367
400
|
|
|
368
401
|
Each record can include an "id" field. Records with matching IDs will be
|
|
@@ -371,25 +404,44 @@ def bulk_upsert(collection: str, records: Sequence[dict[str, Any]]) -> dict[str,
|
|
|
371
404
|
Args:
|
|
372
405
|
collection: Collection name or ID
|
|
373
406
|
records: List of records (max 1000)
|
|
407
|
+
transaction: If True, use all-or-nothing semantics (rollback on any failure).
|
|
408
|
+
If False (default), partial success is allowed.
|
|
374
409
|
|
|
375
410
|
Returns:
|
|
376
|
-
Result with succeeded/failed counts and created record IDs
|
|
411
|
+
Result with succeeded/failed counts and created record IDs:
|
|
412
|
+
{
|
|
413
|
+
"succeeded": 2,
|
|
414
|
+
"failed": 0,
|
|
415
|
+
"errors": [],
|
|
416
|
+
"records": [{"id": "..."}, ...],
|
|
417
|
+
"rolled_back": false # only present if transaction=True and failed
|
|
418
|
+
}
|
|
377
419
|
|
|
378
420
|
Example:
|
|
379
421
|
>>> result = pb.bulk_upsert("deposits", [
|
|
380
422
|
... {"id": "existing_id", "amount": 100},
|
|
381
423
|
... {"amount": 200}, # creates new record
|
|
382
424
|
... ])
|
|
425
|
+
|
|
426
|
+
>>> # Use transaction mode for all-or-nothing
|
|
427
|
+
>>> result = pb.bulk_upsert("deposits", records, transaction=True)
|
|
383
428
|
"""
|
|
384
|
-
return _bulk_upsert_records(collection, records)
|
|
429
|
+
return _bulk_upsert_records(collection, records, transaction=transaction)
|
|
385
430
|
|
|
386
431
|
|
|
387
|
-
def bulk_insert(
|
|
432
|
+
def bulk_insert(
|
|
433
|
+
collection: str,
|
|
434
|
+
records: Sequence[dict[str, Any]],
|
|
435
|
+
*,
|
|
436
|
+
transaction: bool = False,
|
|
437
|
+
) -> dict[str, Any]:
|
|
388
438
|
"""Insert multiple new records.
|
|
389
439
|
|
|
390
440
|
Args:
|
|
391
441
|
collection: Collection name or ID
|
|
392
442
|
records: List of records to create (max 1000)
|
|
443
|
+
transaction: If True, use all-or-nothing semantics (rollback on any failure).
|
|
444
|
+
If False (default), partial success is allowed.
|
|
393
445
|
|
|
394
446
|
Returns:
|
|
395
447
|
Result with succeeded/failed counts and created record IDs:
|
|
@@ -397,7 +449,8 @@ def bulk_insert(collection: str, records: Sequence[dict[str, Any]]) -> dict[str,
|
|
|
397
449
|
"succeeded": 2,
|
|
398
450
|
"failed": 0,
|
|
399
451
|
"errors": [],
|
|
400
|
-
"records": [{"id": "..."}, {"id": "..."}]
|
|
452
|
+
"records": [{"id": "..."}, {"id": "..."}],
|
|
453
|
+
"rolled_back": false # only present if transaction=True and failed
|
|
401
454
|
}
|
|
402
455
|
|
|
403
456
|
Example:
|
|
@@ -407,8 +460,11 @@ def bulk_insert(collection: str, records: Sequence[dict[str, Any]]) -> dict[str,
|
|
|
407
460
|
... ])
|
|
408
461
|
>>> for rec in result["records"]:
|
|
409
462
|
... print(f"Created: {rec['id']}")
|
|
463
|
+
|
|
464
|
+
>>> # Use transaction mode for all-or-nothing
|
|
465
|
+
>>> result = pb.bulk_insert("deposits", records, transaction=True)
|
|
410
466
|
"""
|
|
411
|
-
return _bulk_insert_records(collection, records)
|
|
467
|
+
return _bulk_insert_records(collection, records, transaction=transaction)
|
|
412
468
|
|
|
413
469
|
|
|
414
470
|
def iter_all(
|
|
@@ -591,12 +591,15 @@ def delete_record(collection_id_or_name: str, record_id: str) -> None:
|
|
|
591
591
|
def bulk_delete_records(
|
|
592
592
|
collection_id_or_name: str,
|
|
593
593
|
record_ids: Sequence[str],
|
|
594
|
+
*,
|
|
595
|
+
transaction: bool = False,
|
|
594
596
|
) -> dict[str, Any]:
|
|
595
597
|
"""Bulk delete records by IDs.
|
|
596
598
|
|
|
597
599
|
Args:
|
|
598
600
|
collection_id_or_name: Collection name or ID
|
|
599
601
|
record_ids: List of record IDs to delete (max 1000)
|
|
602
|
+
transaction: If True, use all-or-nothing semantics (rollback on any failure)
|
|
600
603
|
|
|
601
604
|
Returns:
|
|
602
605
|
Result with succeeded/failed counts and any errors
|
|
@@ -607,46 +610,54 @@ def bulk_delete_records(
|
|
|
607
610
|
raise ValueError("record_ids is required")
|
|
608
611
|
|
|
609
612
|
path = f"collections/{collection_id_or_name}/records/bulk/delete"
|
|
610
|
-
|
|
613
|
+
body: dict[str, Any] = {"ids": list(record_ids)}
|
|
614
|
+
if transaction:
|
|
615
|
+
body["transaction"] = True
|
|
616
|
+
result = _api_request("POST", path, json_body=body)
|
|
611
617
|
return result if isinstance(result, dict) else {}
|
|
612
618
|
|
|
613
619
|
|
|
614
620
|
def bulk_update_records(
|
|
615
621
|
collection_id_or_name: str,
|
|
616
|
-
|
|
617
|
-
|
|
622
|
+
records: Sequence[Mapping[str, Any]],
|
|
623
|
+
*,
|
|
624
|
+
transaction: bool = False,
|
|
618
625
|
) -> dict[str, Any]:
|
|
619
|
-
"""Update multiple records with
|
|
626
|
+
"""Update multiple records with individual data per record.
|
|
620
627
|
|
|
621
628
|
Args:
|
|
622
629
|
collection_id_or_name: Collection name or ID
|
|
623
|
-
|
|
624
|
-
|
|
630
|
+
records: List of records to update (max 1000). Each record must have an 'id' field.
|
|
631
|
+
transaction: If True, use all-or-nothing semantics (rollback on any failure)
|
|
625
632
|
|
|
626
633
|
Returns:
|
|
627
634
|
Result with succeeded/failed counts
|
|
628
635
|
"""
|
|
629
636
|
if not collection_id_or_name:
|
|
630
637
|
raise ValueError("collection_id_or_name is required")
|
|
631
|
-
if not
|
|
632
|
-
raise ValueError("
|
|
633
|
-
if not data:
|
|
634
|
-
raise ValueError("data is required")
|
|
638
|
+
if not records:
|
|
639
|
+
raise ValueError("records is required")
|
|
635
640
|
|
|
636
641
|
path = f"collections/{collection_id_or_name}/records/bulk/update"
|
|
637
|
-
|
|
642
|
+
body: dict[str, Any] = {"records": [dict(r) for r in records]}
|
|
643
|
+
if transaction:
|
|
644
|
+
body["transaction"] = True
|
|
645
|
+
result = _api_request("POST", path, json_body=body)
|
|
638
646
|
return result if isinstance(result, dict) else {}
|
|
639
647
|
|
|
640
648
|
|
|
641
649
|
def bulk_upsert_records(
|
|
642
650
|
collection_id_or_name: str,
|
|
643
651
|
records: Sequence[Mapping[str, Any]],
|
|
652
|
+
*,
|
|
653
|
+
transaction: bool = False,
|
|
644
654
|
) -> dict[str, Any]:
|
|
645
655
|
"""Upsert multiple records (create or update by ID).
|
|
646
656
|
|
|
647
657
|
Args:
|
|
648
658
|
collection_id_or_name: Collection name or ID
|
|
649
659
|
records: List of records (max 1000). Include 'id' field to update existing.
|
|
660
|
+
transaction: If True, use all-or-nothing semantics (rollback on any failure)
|
|
650
661
|
|
|
651
662
|
Returns:
|
|
652
663
|
Result with succeeded/failed counts and created record IDs
|
|
@@ -657,19 +668,25 @@ def bulk_upsert_records(
|
|
|
657
668
|
raise ValueError("records is required")
|
|
658
669
|
|
|
659
670
|
path = f"collections/{collection_id_or_name}/records/bulk/upsert"
|
|
660
|
-
|
|
671
|
+
body: dict[str, Any] = {"records": [dict(r) for r in records]}
|
|
672
|
+
if transaction:
|
|
673
|
+
body["transaction"] = True
|
|
674
|
+
result = _api_request("POST", path, json_body=body)
|
|
661
675
|
return result if isinstance(result, dict) else {}
|
|
662
676
|
|
|
663
677
|
|
|
664
678
|
def bulk_insert_records(
|
|
665
679
|
collection_id_or_name: str,
|
|
666
680
|
records: Sequence[Mapping[str, Any]],
|
|
681
|
+
*,
|
|
682
|
+
transaction: bool = False,
|
|
667
683
|
) -> dict[str, Any]:
|
|
668
684
|
"""Insert multiple new records.
|
|
669
685
|
|
|
670
686
|
Args:
|
|
671
687
|
collection_id_or_name: Collection name or ID
|
|
672
688
|
records: List of records to create (max 1000)
|
|
689
|
+
transaction: If True, use all-or-nothing semantics (rollback on any failure)
|
|
673
690
|
|
|
674
691
|
Returns:
|
|
675
692
|
Result with succeeded/failed counts and created record IDs
|
|
@@ -680,7 +697,10 @@ def bulk_insert_records(
|
|
|
680
697
|
raise ValueError("records is required")
|
|
681
698
|
|
|
682
699
|
path = f"collections/{collection_id_or_name}/records/bulk/insert"
|
|
683
|
-
|
|
700
|
+
body: dict[str, Any] = {"records": [dict(r) for r in records]}
|
|
701
|
+
if transaction:
|
|
702
|
+
body["transaction"] = True
|
|
703
|
+
result = _api_request("POST", path, json_body=body)
|
|
684
704
|
return result if isinstance(result, dict) else {}
|
|
685
705
|
|
|
686
706
|
|
|
@@ -852,3 +852,45 @@ def test_claim_locks_custom_provenance(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
|
852
852
|
body = captured.get("json_body")
|
|
853
853
|
assert isinstance(body, dict)
|
|
854
854
|
assert body["provenance"] == custom_prov
|
|
855
|
+
|
|
856
|
+
|
|
857
|
+
def test_bulk_update_records(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
858
|
+
monkeypatch.setenv(sdk.TOKEN_ENV, "tok")
|
|
859
|
+
|
|
860
|
+
captured: dict[str, object] = {}
|
|
861
|
+
|
|
862
|
+
def fake_api(method: str, path: str, **kwargs: object) -> dict[str, object]:
|
|
863
|
+
captured["method"] = method
|
|
864
|
+
captured["path"] = path
|
|
865
|
+
captured["kwargs"] = kwargs
|
|
866
|
+
return {"succeeded": 2, "failed": 0, "errors": []}
|
|
867
|
+
|
|
868
|
+
monkeypatch.setattr(sdk, "_api_request", fake_api)
|
|
869
|
+
|
|
870
|
+
result = sdk.bulk_update_records(
|
|
871
|
+
"test_collection",
|
|
872
|
+
[
|
|
873
|
+
{"id": "rec1", "status": "approved", "amount": 100},
|
|
874
|
+
{"id": "rec2", "status": "rejected", "amount": 200},
|
|
875
|
+
],
|
|
876
|
+
)
|
|
877
|
+
|
|
878
|
+
assert result["succeeded"] == 2
|
|
879
|
+
assert result["failed"] == 0
|
|
880
|
+
assert captured["method"] == "POST"
|
|
881
|
+
assert captured["path"] == "collections/test_collection/records/bulk/update"
|
|
882
|
+
kwargs = captured["kwargs"]
|
|
883
|
+
assert "json_body" in kwargs
|
|
884
|
+
body = kwargs["json_body"]
|
|
885
|
+
assert isinstance(body, dict)
|
|
886
|
+
assert "records" in body
|
|
887
|
+
assert len(body["records"]) == 2
|
|
888
|
+
assert body["records"][0]["id"] == "rec1"
|
|
889
|
+
assert body["records"][0]["status"] == "approved"
|
|
890
|
+
assert body["records"][1]["id"] == "rec2"
|
|
891
|
+
assert body["records"][1]["status"] == "rejected"
|
|
892
|
+
|
|
893
|
+
|
|
894
|
+
def test_bulk_update_records_requires_records() -> None:
|
|
895
|
+
with pytest.raises(ValueError, match="records is required"):
|
|
896
|
+
sdk.bulk_update_records("test_collection", [])
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|