@peerbit/native-backbone 0.1.1 → 0.1.3
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.
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +18 -14
- package/dist/src/index.js.map +1 -1
- package/dist/wasm/native_backbone.d.ts +64 -64
- package/dist/wasm/native_backbone.js +3 -0
- package/dist/wasm/native_backbone_bg.wasm +0 -0
- package/dist/wasm/native_backbone_bg.wasm.d.ts +64 -64
- package/package.json +1 -1
- package/src/append_tx/committed_latest.rs +390 -317
- package/src/append_tx/committed_no_next.rs +66 -64
- package/src/append_tx/facts.rs +213 -147
- package/src/append_tx/mod.rs +160 -58
- package/src/append_tx/storage.rs +52 -28
- package/src/coordinates.rs +135 -44
- package/src/documents.rs +340 -100
- package/src/error.rs +244 -0
- package/src/index.ts +25 -21
- package/src/js_interop.rs +230 -90
- package/src/lib.rs +4 -0
- package/src/raw_receive.rs +182 -107
- package/src/shared_log_plan.rs +65 -23
- package/src/sync_send.rs +19 -3
- package/src/time.rs +14 -0
- package/src/wire_sync.rs +147 -36
package/src/documents.rs
CHANGED
|
@@ -13,12 +13,12 @@ use peerbit_log_rust::entry_v0_signature_public_key_from_storage_bytes;
|
|
|
13
13
|
use std::collections::HashMap;
|
|
14
14
|
use wasm_bindgen::prelude::*;
|
|
15
15
|
|
|
16
|
+
use crate::error::BackboneError;
|
|
16
17
|
use crate::js_interop::{
|
|
17
18
|
append_journal_delete_record, append_journal_put_record, array_strings, bytes_vec_from_array,
|
|
18
|
-
clear_journal_prefix,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
write_u8,
|
|
19
|
+
clear_journal_prefix, ensure_same_len, js_get, optional_string, parse_optional_u64_string,
|
|
20
|
+
parse_u64_string, read_bytes, read_encoded_string, read_u32, read_u64, strings_from_array,
|
|
21
|
+
write_bool, write_bytes, write_string, write_u32, write_u64, write_u8,
|
|
22
22
|
};
|
|
23
23
|
use crate::{NativePeerbitBackbone, NATIVE_BACKBONE_BYTE_EXACT_INDEX_LIMIT};
|
|
24
24
|
|
|
@@ -224,13 +224,15 @@ pub(crate) fn document_index_cached_projection_plain_put_payload_append_commit(
|
|
|
224
224
|
})
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
pub(crate) fn plain_put_document_bytes_from_payload(
|
|
227
|
+
pub(crate) fn plain_put_document_bytes_from_payload(
|
|
228
|
+
payload_data: &[u8],
|
|
229
|
+
) -> Result<&[u8], BackboneError> {
|
|
228
230
|
const PLAIN_PUT_OPERATION_PREFIX_LENGTH: usize = 6;
|
|
229
231
|
if payload_data.len() < PLAIN_PUT_OPERATION_PREFIX_LENGTH {
|
|
230
|
-
return Err(
|
|
232
|
+
return Err(BackboneError::PlainPutPayloadTooShort);
|
|
231
233
|
}
|
|
232
234
|
if payload_data[0] != 0 || payload_data[1] != 3 {
|
|
233
|
-
return Err(
|
|
235
|
+
return Err(BackboneError::Expected("native plain put payload"));
|
|
234
236
|
}
|
|
235
237
|
let declared_len = u32::from_le_bytes([
|
|
236
238
|
payload_data[2],
|
|
@@ -240,7 +242,7 @@ pub(crate) fn plain_put_document_bytes_from_payload(payload_data: &[u8]) -> Resu
|
|
|
240
242
|
]) as usize;
|
|
241
243
|
let document_bytes = &payload_data[PLAIN_PUT_OPERATION_PREFIX_LENGTH..];
|
|
242
244
|
if document_bytes.len() != declared_len {
|
|
243
|
-
return Err(
|
|
245
|
+
return Err(BackboneError::PlainPutPayloadLengthMismatch);
|
|
244
246
|
}
|
|
245
247
|
Ok(document_bytes)
|
|
246
248
|
}
|
|
@@ -330,12 +332,12 @@ fn encode_document_signer_fact(fact: &DocumentPreviousSignerFact) -> Vec<u8> {
|
|
|
330
332
|
out
|
|
331
333
|
}
|
|
332
334
|
|
|
333
|
-
fn decode_document_signer_fact(bytes: &[u8]) -> Result<DocumentPreviousSignerFact,
|
|
335
|
+
fn decode_document_signer_fact(bytes: &[u8]) -> Result<DocumentPreviousSignerFact, BackboneError> {
|
|
334
336
|
let mut offset = 0usize;
|
|
335
337
|
let head = read_encoded_string(bytes, &mut offset, "document signer head")?;
|
|
336
338
|
let public_key = read_bytes(bytes, &mut offset, "document signer public key")?;
|
|
337
339
|
if offset != bytes.len() {
|
|
338
|
-
return Err(
|
|
340
|
+
return Err(BackboneError::TrailingDocumentSignerFactBytes);
|
|
339
341
|
}
|
|
340
342
|
Ok(DocumentPreviousSignerFact { head, public_key })
|
|
341
343
|
}
|
|
@@ -346,7 +348,7 @@ pub(crate) fn encode_document_context_suffix(
|
|
|
346
348
|
head: &str,
|
|
347
349
|
gid: &str,
|
|
348
350
|
size: u32,
|
|
349
|
-
) -> Result<Vec<u8>,
|
|
351
|
+
) -> Result<Vec<u8>, BackboneError> {
|
|
350
352
|
let capacity = 1usize
|
|
351
353
|
.checked_add(8)
|
|
352
354
|
.and_then(|value| value.checked_add(8))
|
|
@@ -355,7 +357,7 @@ pub(crate) fn encode_document_context_suffix(
|
|
|
355
357
|
.and_then(|value| value.checked_add(4))
|
|
356
358
|
.and_then(|value| value.checked_add(gid.len()))
|
|
357
359
|
.and_then(|value| value.checked_add(4))
|
|
358
|
-
.
|
|
360
|
+
.ok_or(BackboneError::DocumentContextSuffixCapacityOverflow)?;
|
|
359
361
|
let mut out = Vec::with_capacity(capacity);
|
|
360
362
|
// Context is @variant(0); keep this byte-for-byte aligned with Borsh.
|
|
361
363
|
out.push(0);
|
|
@@ -376,24 +378,36 @@ enum ProjectionValue {
|
|
|
376
378
|
None,
|
|
377
379
|
}
|
|
378
380
|
|
|
379
|
-
fn read_u8_projection(
|
|
381
|
+
fn read_u8_projection(
|
|
382
|
+
bytes: &[u8],
|
|
383
|
+
offset: &mut usize,
|
|
384
|
+
label: &'static str,
|
|
385
|
+
) -> Result<u8, BackboneError> {
|
|
380
386
|
if *offset >= bytes.len() {
|
|
381
|
-
return Err(
|
|
387
|
+
return Err(BackboneError::Truncated(label));
|
|
382
388
|
}
|
|
383
389
|
let value = bytes[*offset];
|
|
384
390
|
*offset += 1;
|
|
385
391
|
Ok(value)
|
|
386
392
|
}
|
|
387
393
|
|
|
388
|
-
fn read_bool_projection(
|
|
394
|
+
fn read_bool_projection(
|
|
395
|
+
bytes: &[u8],
|
|
396
|
+
offset: &mut usize,
|
|
397
|
+
label: &'static str,
|
|
398
|
+
) -> Result<bool, BackboneError> {
|
|
389
399
|
match read_u8_projection(bytes, offset, label)? {
|
|
390
400
|
0 => Ok(false),
|
|
391
401
|
1 => Ok(true),
|
|
392
|
-
_ => Err(
|
|
402
|
+
_ => Err(BackboneError::InvalidBool(label)),
|
|
393
403
|
}
|
|
394
404
|
}
|
|
395
405
|
|
|
396
|
-
fn skip_projection_value(
|
|
406
|
+
fn skip_projection_value(
|
|
407
|
+
bytes: &[u8],
|
|
408
|
+
offset: &mut usize,
|
|
409
|
+
kind: &str,
|
|
410
|
+
) -> Result<(), BackboneError> {
|
|
397
411
|
match kind {
|
|
398
412
|
"string" => {
|
|
399
413
|
read_encoded_string(bytes, offset, "projected string")?;
|
|
@@ -419,7 +433,7 @@ fn skip_projection_value(bytes: &[u8], offset: &mut usize, kind: &str) -> Result
|
|
|
419
433
|
if has_value == 1 {
|
|
420
434
|
skip_projection_value(bytes, offset, &kind["option:".len()..])?;
|
|
421
435
|
} else if has_value != 0 {
|
|
422
|
-
return Err(
|
|
436
|
+
return Err(BackboneError::InvalidProjectionOptionMarker);
|
|
423
437
|
}
|
|
424
438
|
}
|
|
425
439
|
"vec:string" => {
|
|
@@ -435,9 +449,7 @@ fn skip_projection_value(bytes: &[u8], offset: &mut usize, kind: &str) -> Result
|
|
|
435
449
|
}
|
|
436
450
|
}
|
|
437
451
|
_ => {
|
|
438
|
-
return Err(
|
|
439
|
-
"Unsupported document projection field type",
|
|
440
|
-
))
|
|
452
|
+
return Err(BackboneError::UnsupportedDocumentProjectionFieldType);
|
|
441
453
|
}
|
|
442
454
|
}
|
|
443
455
|
Ok(())
|
|
@@ -447,7 +459,7 @@ fn read_projection_value(
|
|
|
447
459
|
bytes: &[u8],
|
|
448
460
|
offset: &mut usize,
|
|
449
461
|
kind: &str,
|
|
450
|
-
) -> Result<ProjectionValue,
|
|
462
|
+
) -> Result<ProjectionValue, BackboneError> {
|
|
451
463
|
match kind {
|
|
452
464
|
"string" => Ok(ProjectionValue::String(read_encoded_string(
|
|
453
465
|
bytes,
|
|
@@ -486,7 +498,7 @@ fn read_projection_value(
|
|
|
486
498
|
"projection option string",
|
|
487
499
|
)?))
|
|
488
500
|
} else {
|
|
489
|
-
Err(
|
|
501
|
+
Err(BackboneError::InvalidProjectionOptionMarker)
|
|
490
502
|
}
|
|
491
503
|
}
|
|
492
504
|
"option:u8" => {
|
|
@@ -498,7 +510,7 @@ fn read_projection_value(
|
|
|
498
510
|
read_u8_projection(bytes, offset, "projection option u8")? as u64,
|
|
499
511
|
))
|
|
500
512
|
} else {
|
|
501
|
-
Err(
|
|
513
|
+
Err(BackboneError::InvalidProjectionOptionMarker)
|
|
502
514
|
}
|
|
503
515
|
}
|
|
504
516
|
"option:u32" => {
|
|
@@ -510,7 +522,7 @@ fn read_projection_value(
|
|
|
510
522
|
read_u32(bytes, offset, "projection option u32")? as u64,
|
|
511
523
|
))
|
|
512
524
|
} else {
|
|
513
|
-
Err(
|
|
525
|
+
Err(BackboneError::InvalidProjectionOptionMarker)
|
|
514
526
|
}
|
|
515
527
|
}
|
|
516
528
|
"option:u64" => {
|
|
@@ -524,7 +536,7 @@ fn read_projection_value(
|
|
|
524
536
|
"projection option u64",
|
|
525
537
|
)?))
|
|
526
538
|
} else {
|
|
527
|
-
Err(
|
|
539
|
+
Err(BackboneError::InvalidProjectionOptionMarker)
|
|
528
540
|
}
|
|
529
541
|
}
|
|
530
542
|
"option:bool" => {
|
|
@@ -538,7 +550,7 @@ fn read_projection_value(
|
|
|
538
550
|
"projection option bool",
|
|
539
551
|
)?))
|
|
540
552
|
} else {
|
|
541
|
-
Err(
|
|
553
|
+
Err(BackboneError::InvalidProjectionOptionMarker)
|
|
542
554
|
}
|
|
543
555
|
}
|
|
544
556
|
"option:bytes" => {
|
|
@@ -552,12 +564,10 @@ fn read_projection_value(
|
|
|
552
564
|
"projection option bytes",
|
|
553
565
|
)?))
|
|
554
566
|
} else {
|
|
555
|
-
Err(
|
|
567
|
+
Err(BackboneError::InvalidProjectionOptionMarker)
|
|
556
568
|
}
|
|
557
569
|
}
|
|
558
|
-
_ => Err(
|
|
559
|
-
"Unsupported projected document field type",
|
|
560
|
-
)),
|
|
570
|
+
_ => Err(BackboneError::UnsupportedProjectedDocumentFieldType),
|
|
561
571
|
}
|
|
562
572
|
}
|
|
563
573
|
|
|
@@ -565,7 +575,7 @@ fn write_projection_value(
|
|
|
565
575
|
out: &mut Vec<u8>,
|
|
566
576
|
kind: &str,
|
|
567
577
|
value: &ProjectionValue,
|
|
568
|
-
) -> Result<(),
|
|
578
|
+
) -> Result<(), BackboneError> {
|
|
569
579
|
match (kind, value) {
|
|
570
580
|
("string", ProjectionValue::String(value)) => write_string(out, value),
|
|
571
581
|
("u8", ProjectionValue::U64(value)) => write_u8(out, *value as u8),
|
|
@@ -604,9 +614,7 @@ fn write_projection_value(
|
|
|
604
614
|
write_bytes(out, value);
|
|
605
615
|
}
|
|
606
616
|
_ => {
|
|
607
|
-
return Err(
|
|
608
|
-
"Projection value does not match output type",
|
|
609
|
-
))
|
|
617
|
+
return Err(BackboneError::ProjectionValueOutputTypeMismatch);
|
|
610
618
|
}
|
|
611
619
|
}
|
|
612
620
|
Ok(())
|
|
@@ -618,32 +626,29 @@ fn read_projected_document_fields(
|
|
|
618
626
|
variant_value: Option<&str>,
|
|
619
627
|
names: &[String],
|
|
620
628
|
types: &[String],
|
|
621
|
-
) -> Result<HashMap<String, ProjectionValue>,
|
|
629
|
+
) -> Result<HashMap<String, ProjectionValue>, BackboneError> {
|
|
622
630
|
if names.len() != types.len() {
|
|
623
|
-
return Err(
|
|
624
|
-
"Document projection plan length mismatch",
|
|
625
|
-
));
|
|
631
|
+
return Err(BackboneError::DocumentProjectionPlanLengthMismatch);
|
|
626
632
|
}
|
|
627
633
|
let mut offset = 0usize;
|
|
628
634
|
match variant_type {
|
|
629
635
|
Some("u8") => {
|
|
630
636
|
let expected = variant_value
|
|
631
|
-
.
|
|
637
|
+
.ok_or(BackboneError::MissingDocumentVariant)?
|
|
632
638
|
.parse::<u8>()
|
|
633
|
-
.map_err(|_|
|
|
639
|
+
.map_err(|_| BackboneError::InvalidDocumentVariant)?;
|
|
634
640
|
if read_u8_projection(encoded_document, &mut offset, "document variant")? != expected {
|
|
635
|
-
return Err(
|
|
641
|
+
return Err(BackboneError::DocumentVariantMismatch);
|
|
636
642
|
}
|
|
637
643
|
}
|
|
638
644
|
Some("string") => {
|
|
639
|
-
let expected =
|
|
640
|
-
variant_value.ok_or_else(|| JsValue::from_str("Missing document variant"))?;
|
|
645
|
+
let expected = variant_value.ok_or(BackboneError::MissingDocumentVariant)?;
|
|
641
646
|
if read_encoded_string(encoded_document, &mut offset, "document variant")? != expected {
|
|
642
|
-
return Err(
|
|
647
|
+
return Err(BackboneError::DocumentVariantMismatch);
|
|
643
648
|
}
|
|
644
649
|
}
|
|
645
650
|
Some("") | None => {}
|
|
646
|
-
_ => return Err(
|
|
651
|
+
_ => return Err(BackboneError::UnsupportedDocumentVariantType),
|
|
647
652
|
}
|
|
648
653
|
let mut out = HashMap::with_capacity(names.len());
|
|
649
654
|
for (name, kind) in names.iter().zip(types.iter()) {
|
|
@@ -666,26 +671,26 @@ fn write_projection_variant(
|
|
|
666
671
|
out: &mut Vec<u8>,
|
|
667
672
|
variant_type: Option<&str>,
|
|
668
673
|
variant_value: Option<&str>,
|
|
669
|
-
) -> Result<(),
|
|
674
|
+
) -> Result<(), BackboneError> {
|
|
670
675
|
match variant_type {
|
|
671
676
|
Some("u8") => {
|
|
672
677
|
let value = variant_value
|
|
673
|
-
.
|
|
678
|
+
.ok_or(BackboneError::MissingOutputVariant)?
|
|
674
679
|
.parse::<u8>()
|
|
675
|
-
.map_err(|_|
|
|
680
|
+
.map_err(|_| BackboneError::InvalidOutputVariant)?;
|
|
676
681
|
write_u8(out, value);
|
|
677
682
|
}
|
|
678
683
|
Some("string") => {
|
|
679
|
-
let value = variant_value.
|
|
684
|
+
let value = variant_value.ok_or(BackboneError::MissingOutputVariant)?;
|
|
680
685
|
write_string(out, value);
|
|
681
686
|
}
|
|
682
687
|
Some("") | None => {}
|
|
683
|
-
_ => return Err(
|
|
688
|
+
_ => return Err(BackboneError::UnsupportedOutputVariantType),
|
|
684
689
|
}
|
|
685
690
|
Ok(())
|
|
686
691
|
}
|
|
687
692
|
|
|
688
|
-
fn parse_projection_plan(plan: &JsValue) -> Result<ParsedProjectionPlan,
|
|
693
|
+
fn parse_projection_plan(plan: &JsValue) -> Result<ParsedProjectionPlan, BackboneError> {
|
|
689
694
|
let document_field_names =
|
|
690
695
|
array_strings(js_get(plan, "documentFieldNames"), "documentFieldNames")?;
|
|
691
696
|
let document_field_types =
|
|
@@ -694,13 +699,25 @@ fn parse_projection_plan(plan: &JsValue) -> Result<ParsedProjectionPlan, JsValue
|
|
|
694
699
|
let source_kinds = array_strings(js_get(plan, "sourceKinds"), "sourceKinds")?;
|
|
695
700
|
let source_values = array_strings(js_get(plan, "sourceValues"), "sourceValues")?;
|
|
696
701
|
if output_field_types.len() != source_kinds.len() || source_kinds.len() != source_values.len() {
|
|
697
|
-
return Err(
|
|
702
|
+
return Err(BackboneError::ProjectionPlanLengthMismatch);
|
|
698
703
|
}
|
|
699
704
|
Ok(ParsedProjectionPlan {
|
|
700
|
-
document_variant_type: optional_string(
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
705
|
+
document_variant_type: optional_string(
|
|
706
|
+
js_get(plan, "documentVariantType"),
|
|
707
|
+
"documentVariantType",
|
|
708
|
+
)?,
|
|
709
|
+
document_variant_value: optional_string(
|
|
710
|
+
js_get(plan, "documentVariantValue"),
|
|
711
|
+
"documentVariantValue",
|
|
712
|
+
)?,
|
|
713
|
+
output_variant_type: optional_string(
|
|
714
|
+
js_get(plan, "outputVariantType"),
|
|
715
|
+
"outputVariantType",
|
|
716
|
+
)?,
|
|
717
|
+
output_variant_value: optional_string(
|
|
718
|
+
js_get(plan, "outputVariantValue"),
|
|
719
|
+
"outputVariantValue",
|
|
720
|
+
)?,
|
|
704
721
|
document_field_names,
|
|
705
722
|
document_field_types,
|
|
706
723
|
output_field_types,
|
|
@@ -718,7 +735,7 @@ pub(crate) fn project_document_index_simple_bytes_with_plan(
|
|
|
718
735
|
gid: &str,
|
|
719
736
|
size: u32,
|
|
720
737
|
signer: Option<&[u8]>,
|
|
721
|
-
) -> Result<Vec<u8>,
|
|
738
|
+
) -> Result<Vec<u8>, BackboneError> {
|
|
722
739
|
let document_values = read_projected_document_fields(
|
|
723
740
|
encoded_document,
|
|
724
741
|
plan.document_variant_type.as_deref(),
|
|
@@ -746,12 +763,12 @@ pub(crate) fn project_document_index_simple_bytes_with_plan(
|
|
|
746
763
|
"head" => ProjectionValue::String(head.to_string()),
|
|
747
764
|
"gid" => ProjectionValue::String(gid.to_string()),
|
|
748
765
|
"size" => ProjectionValue::U64(size as u64),
|
|
749
|
-
_ => return Err(
|
|
766
|
+
_ => return Err(BackboneError::UnsupportedContextProjectionSource),
|
|
750
767
|
},
|
|
751
768
|
"entryFirstSignerPublicKey" => signer
|
|
752
769
|
.map(|bytes| ProjectionValue::Bytes(bytes.to_vec()))
|
|
753
770
|
.unwrap_or(ProjectionValue::None),
|
|
754
|
-
_ => return Err(
|
|
771
|
+
_ => return Err(BackboneError::UnsupportedProjectionSourceKind),
|
|
755
772
|
};
|
|
756
773
|
write_projection_value(&mut out, &plan.output_field_types[index], &value)?;
|
|
757
774
|
}
|
|
@@ -768,7 +785,7 @@ fn project_document_index_simple_bytes(
|
|
|
768
785
|
gid: &str,
|
|
769
786
|
size: u32,
|
|
770
787
|
signer: JsValue,
|
|
771
|
-
) -> Result<Vec<u8>,
|
|
788
|
+
) -> Result<Vec<u8>, BackboneError> {
|
|
772
789
|
let plan = parse_projection_plan(plan)?;
|
|
773
790
|
let created = parse_u64_string(created, "created")?;
|
|
774
791
|
let modified = parse_u64_string(modified, "modified")?;
|
|
@@ -795,7 +812,7 @@ impl NativePeerbitBackbone {
|
|
|
795
812
|
&mut self,
|
|
796
813
|
schema_ir_bytes: Vec<u8>,
|
|
797
814
|
) -> Result<Array, JsValue> {
|
|
798
|
-
let schema_ir = decode_native_schema_ir(&schema_ir_bytes).map_err(
|
|
815
|
+
let schema_ir = decode_native_schema_ir(&schema_ir_bytes).map_err(BackboneError::from)?;
|
|
799
816
|
let stats = schema_ir.stats();
|
|
800
817
|
self.document_schema_ir = Some(schema_ir);
|
|
801
818
|
self.rebuild_document_index_from_values()?;
|
|
@@ -811,7 +828,7 @@ impl NativePeerbitBackbone {
|
|
|
811
828
|
return Ok(());
|
|
812
829
|
}
|
|
813
830
|
self.document_byte_element_index_limit = limit;
|
|
814
|
-
self.rebuild_document_index_from_values()
|
|
831
|
+
Ok(self.rebuild_document_index_from_values()?)
|
|
815
832
|
}
|
|
816
833
|
|
|
817
834
|
pub fn set_document_context_head_field(&mut self, field: u32) {
|
|
@@ -980,8 +997,8 @@ impl NativePeerbitBackbone {
|
|
|
980
997
|
query_bytes: Vec<u8>,
|
|
981
998
|
sort_bytes: Vec<u8>,
|
|
982
999
|
) -> Result<Array, JsValue> {
|
|
983
|
-
let query = decode_query(&query_bytes).map_err(
|
|
984
|
-
let sort = decode_sort(&sort_bytes).map_err(
|
|
1000
|
+
let query = decode_query(&query_bytes).map_err(BackboneError::Message)?;
|
|
1001
|
+
let sort = decode_sort(&sort_bytes).map_err(BackboneError::Message)?;
|
|
985
1002
|
let keys = self.document_index.search(&query, &sort, None);
|
|
986
1003
|
Ok(self.document_entries_for_keys(&keys))
|
|
987
1004
|
}
|
|
@@ -993,8 +1010,8 @@ impl NativePeerbitBackbone {
|
|
|
993
1010
|
offset: usize,
|
|
994
1011
|
limit: usize,
|
|
995
1012
|
) -> Result<Array, JsValue> {
|
|
996
|
-
let query = decode_query(&query_bytes).map_err(
|
|
997
|
-
let sort = decode_sort(&sort_bytes).map_err(
|
|
1013
|
+
let query = decode_query(&query_bytes).map_err(BackboneError::Message)?;
|
|
1014
|
+
let sort = decode_sort(&sort_bytes).map_err(BackboneError::Message)?;
|
|
998
1015
|
let keys = self
|
|
999
1016
|
.document_index
|
|
1000
1017
|
.search_page(&query, &sort, offset, Some(limit));
|
|
@@ -1002,16 +1019,16 @@ impl NativePeerbitBackbone {
|
|
|
1002
1019
|
}
|
|
1003
1020
|
|
|
1004
1021
|
pub fn document_count(&self, query_bytes: Vec<u8>) -> Result<usize, JsValue> {
|
|
1005
|
-
let query = decode_query(&query_bytes).map_err(
|
|
1022
|
+
let query = decode_query(&query_bytes).map_err(BackboneError::Message)?;
|
|
1006
1023
|
Ok(self.document_index.count(&query) as usize)
|
|
1007
1024
|
}
|
|
1008
1025
|
|
|
1009
1026
|
pub fn document_sum(&self, query_bytes: Vec<u8>, field: u32) -> Result<Array, JsValue> {
|
|
1010
|
-
let query = decode_query(&query_bytes).map_err(
|
|
1027
|
+
let query = decode_query(&query_bytes).map_err(BackboneError::Message)?;
|
|
1011
1028
|
let sum = self
|
|
1012
1029
|
.document_index
|
|
1013
1030
|
.sum(&query, FieldPath::Id(field))
|
|
1014
|
-
.map_err(
|
|
1031
|
+
.map_err(BackboneError::Message)?;
|
|
1015
1032
|
Ok(sum_to_js(sum))
|
|
1016
1033
|
}
|
|
1017
1034
|
|
|
@@ -1181,12 +1198,12 @@ impl NativePeerbitBackbone {
|
|
|
1181
1198
|
let mut entries = if snapshot.length() == 0 {
|
|
1182
1199
|
Default::default()
|
|
1183
1200
|
} else {
|
|
1184
|
-
decode_key_value_snapshot(&snapshot.to_vec()).map_err(
|
|
1201
|
+
decode_key_value_snapshot(&snapshot.to_vec()).map_err(BackboneError::from)?
|
|
1185
1202
|
};
|
|
1186
1203
|
let journal_records = if journal.length() == 0 {
|
|
1187
1204
|
Vec::new()
|
|
1188
1205
|
} else {
|
|
1189
|
-
decode_journal(&journal.to_vec()).map_err(
|
|
1206
|
+
decode_journal(&journal.to_vec()).map_err(BackboneError::from)?
|
|
1190
1207
|
};
|
|
1191
1208
|
let operations = journal_records.len();
|
|
1192
1209
|
for record in journal_records {
|
|
@@ -1268,12 +1285,12 @@ impl NativePeerbitBackbone {
|
|
|
1268
1285
|
let mut entries = if snapshot.length() == 0 {
|
|
1269
1286
|
Default::default()
|
|
1270
1287
|
} else {
|
|
1271
|
-
decode_key_value_snapshot(&snapshot.to_vec()).map_err(
|
|
1288
|
+
decode_key_value_snapshot(&snapshot.to_vec()).map_err(BackboneError::from)?
|
|
1272
1289
|
};
|
|
1273
1290
|
let journal_records = if journal.length() == 0 {
|
|
1274
1291
|
Vec::new()
|
|
1275
1292
|
} else {
|
|
1276
|
-
decode_journal(&journal.to_vec()).map_err(
|
|
1293
|
+
decode_journal(&journal.to_vec()).map_err(BackboneError::from)?
|
|
1277
1294
|
};
|
|
1278
1295
|
let operations = journal_records.len();
|
|
1279
1296
|
for record in journal_records {
|
|
@@ -1322,7 +1339,7 @@ impl NativePeerbitBackbone {
|
|
|
1322
1339
|
pub(crate) fn document_context_facts_by_key(
|
|
1323
1340
|
&self,
|
|
1324
1341
|
key: &str,
|
|
1325
|
-
) -> Result<Option<DocumentContextFacts>,
|
|
1342
|
+
) -> Result<Option<DocumentContextFacts>, BackboneError> {
|
|
1326
1343
|
let Some(document_fields) = self.document_index.document_fields_by_id(key) else {
|
|
1327
1344
|
return Ok(None);
|
|
1328
1345
|
};
|
|
@@ -1332,21 +1349,21 @@ impl NativePeerbitBackbone {
|
|
|
1332
1349
|
fn document_context_facts_from_fields(
|
|
1333
1350
|
&self,
|
|
1334
1351
|
document_fields: &DocumentFields,
|
|
1335
|
-
) -> Result<Option<DocumentContextFacts>,
|
|
1352
|
+
) -> Result<Option<DocumentContextFacts>, BackboneError> {
|
|
1336
1353
|
let Some(fields) = self.document_context_fields else {
|
|
1337
1354
|
return Ok(None);
|
|
1338
1355
|
};
|
|
1339
1356
|
let created = document_u64_field(document_fields, fields.created)
|
|
1340
|
-
.
|
|
1357
|
+
.ok_or(BackboneError::MissingDocumentContextField("created"))?;
|
|
1341
1358
|
let modified = document_u64_field(document_fields, fields.modified)
|
|
1342
|
-
.
|
|
1359
|
+
.ok_or(BackboneError::MissingDocumentContextField("modified"))?;
|
|
1343
1360
|
let head = document_string_field(document_fields, fields.head)
|
|
1344
|
-
.
|
|
1361
|
+
.ok_or(BackboneError::MissingDocumentContextField("head"))?;
|
|
1345
1362
|
let gid = document_string_field(document_fields, fields.gid)
|
|
1346
|
-
.
|
|
1363
|
+
.ok_or(BackboneError::MissingDocumentContextField("gid"))?;
|
|
1347
1364
|
let size = document_u64_field(document_fields, fields.size)
|
|
1348
1365
|
.and_then(|value| u32::try_from(value).ok())
|
|
1349
|
-
.
|
|
1366
|
+
.ok_or(BackboneError::MissingDocumentContextField("size"))?;
|
|
1350
1367
|
Ok(Some(DocumentContextFacts {
|
|
1351
1368
|
created,
|
|
1352
1369
|
modified,
|
|
@@ -1390,7 +1407,7 @@ impl NativePeerbitBackbone {
|
|
|
1390
1407
|
new_head: Option<&str>,
|
|
1391
1408
|
previous_head: Option<&str>,
|
|
1392
1409
|
record_document_journal: bool,
|
|
1393
|
-
) -> Result<(),
|
|
1410
|
+
) -> Result<(), BackboneError> {
|
|
1394
1411
|
let prepared = self.prepare_document_encoded_parts_put(
|
|
1395
1412
|
key,
|
|
1396
1413
|
value_prefix_bytes,
|
|
@@ -1416,31 +1433,31 @@ impl NativePeerbitBackbone {
|
|
|
1416
1433
|
new_head: Option<&str>,
|
|
1417
1434
|
previous_head: Option<&str>,
|
|
1418
1435
|
record_document_journal: bool,
|
|
1419
|
-
) -> Result<PreparedDocumentEncodedPartsPut,
|
|
1436
|
+
) -> Result<PreparedDocumentEncodedPartsPut, BackboneError> {
|
|
1420
1437
|
self.document_byte_element_index_limit = byte_element_index_limit;
|
|
1421
1438
|
let profile_enabled = self.append_profile_enabled;
|
|
1422
|
-
let extract_started = profile_enabled.then(
|
|
1439
|
+
let extract_started = profile_enabled.then(crate::time::now_ms);
|
|
1423
1440
|
let fields = {
|
|
1424
|
-
let schema_ir = self
|
|
1425
|
-
|
|
1426
|
-
|
|
1441
|
+
let schema_ir = self
|
|
1442
|
+
.document_schema_ir
|
|
1443
|
+
.as_ref()
|
|
1444
|
+
.ok_or(BackboneError::DocumentSchemaIrNotConfigured)?;
|
|
1427
1445
|
extract_encoded_document_fields_from_parts_with_byte_limits(
|
|
1428
1446
|
&schema_ir,
|
|
1429
1447
|
&value_prefix_bytes,
|
|
1430
1448
|
&value_suffix_bytes,
|
|
1431
1449
|
byte_element_index_limit,
|
|
1432
1450
|
NATIVE_BACKBONE_BYTE_EXACT_INDEX_LIMIT,
|
|
1433
|
-
)
|
|
1434
|
-
.map_err(js_error)?
|
|
1451
|
+
)?
|
|
1435
1452
|
};
|
|
1436
1453
|
if let Some(started) = extract_started {
|
|
1437
|
-
self.append_profile.document_index_extract_ms +=
|
|
1454
|
+
self.append_profile.document_index_extract_ms += crate::time::now_ms() - started;
|
|
1438
1455
|
}
|
|
1439
|
-
let value_build_started = profile_enabled.then(
|
|
1456
|
+
let value_build_started = profile_enabled.then(crate::time::now_ms);
|
|
1440
1457
|
value_prefix_bytes.reserve(value_suffix_bytes.len());
|
|
1441
1458
|
value_prefix_bytes.extend_from_slice(&value_suffix_bytes);
|
|
1442
1459
|
if let Some(started) = value_build_started {
|
|
1443
|
-
self.append_profile.document_index_value_build_ms +=
|
|
1460
|
+
self.append_profile.document_index_value_build_ms += crate::time::now_ms() - started;
|
|
1444
1461
|
}
|
|
1445
1462
|
Ok(PreparedDocumentEncodedPartsPut {
|
|
1446
1463
|
key,
|
|
@@ -1472,7 +1489,7 @@ impl NativePeerbitBackbone {
|
|
|
1472
1489
|
if should_record_document_journal {
|
|
1473
1490
|
self.push_document_journal_put(&key, &value_bytes);
|
|
1474
1491
|
}
|
|
1475
|
-
let value_put_started = profile_enabled.then(
|
|
1492
|
+
let value_put_started = profile_enabled.then(crate::time::now_ms);
|
|
1476
1493
|
let was_existing = if known_existing {
|
|
1477
1494
|
self.document_values.put(key.clone(), value_bytes);
|
|
1478
1495
|
true
|
|
@@ -1482,16 +1499,16 @@ impl NativePeerbitBackbone {
|
|
|
1482
1499
|
.is_some()
|
|
1483
1500
|
};
|
|
1484
1501
|
if let Some(started) = value_put_started {
|
|
1485
|
-
self.append_profile.document_value_put_ms +=
|
|
1502
|
+
self.append_profile.document_value_put_ms += crate::time::now_ms() - started;
|
|
1486
1503
|
}
|
|
1487
|
-
let index_put_started = profile_enabled.then(
|
|
1504
|
+
let index_put_started = profile_enabled.then(crate::time::now_ms);
|
|
1488
1505
|
if known_existing || was_existing {
|
|
1489
1506
|
self.document_index.put(&key, fields);
|
|
1490
1507
|
} else {
|
|
1491
1508
|
self.document_index.put_new_unchecked(&key, fields);
|
|
1492
1509
|
}
|
|
1493
1510
|
if let Some(started) = index_put_started {
|
|
1494
|
-
self.append_profile.document_index_put_ms +=
|
|
1511
|
+
self.append_profile.document_index_put_ms += crate::time::now_ms() - started;
|
|
1495
1512
|
}
|
|
1496
1513
|
self.update_document_head_key(
|
|
1497
1514
|
&key,
|
|
@@ -1526,7 +1543,7 @@ impl NativePeerbitBackbone {
|
|
|
1526
1543
|
.insert(new_head.to_string(), key.to_string());
|
|
1527
1544
|
}
|
|
1528
1545
|
|
|
1529
|
-
fn refresh_document_previous_signer_fact(&mut self, key: &str) -> Result<(),
|
|
1546
|
+
fn refresh_document_previous_signer_fact(&mut self, key: &str) -> Result<(), BackboneError> {
|
|
1530
1547
|
let Some(context) = self.document_context_facts_by_key(key)? else {
|
|
1531
1548
|
self.delete_document_previous_signer_fact(key, true);
|
|
1532
1549
|
return Ok(());
|
|
@@ -1578,7 +1595,7 @@ impl NativePeerbitBackbone {
|
|
|
1578
1595
|
self.document_signer_journal_record_count = 0;
|
|
1579
1596
|
}
|
|
1580
1597
|
|
|
1581
|
-
fn rebuild_document_index_from_values(&mut self) -> Result<(),
|
|
1598
|
+
fn rebuild_document_index_from_values(&mut self) -> Result<(), BackboneError> {
|
|
1582
1599
|
let Some(schema_ir) = self.document_schema_ir.clone() else {
|
|
1583
1600
|
self.document_index.clear();
|
|
1584
1601
|
self.document_key_by_head.clear();
|
|
@@ -1600,8 +1617,7 @@ impl NativePeerbitBackbone {
|
|
|
1600
1617
|
&[],
|
|
1601
1618
|
self.document_byte_element_index_limit,
|
|
1602
1619
|
NATIVE_BACKBONE_BYTE_EXACT_INDEX_LIMIT,
|
|
1603
|
-
)
|
|
1604
|
-
.map_err(js_error)?;
|
|
1620
|
+
)?;
|
|
1605
1621
|
if let Some(context) = self.document_context_facts_from_fields(&fields)? {
|
|
1606
1622
|
self.document_key_by_head.insert(context.head, key.clone());
|
|
1607
1623
|
}
|
|
@@ -1696,3 +1712,227 @@ impl NativePeerbitBackbone {
|
|
|
1696
1712
|
self.document_key_by_head.reserve(batch_len);
|
|
1697
1713
|
}
|
|
1698
1714
|
}
|
|
1715
|
+
|
|
1716
|
+
#[cfg(test)]
|
|
1717
|
+
mod tests {
|
|
1718
|
+
use super::*;
|
|
1719
|
+
|
|
1720
|
+
fn projection_plan(
|
|
1721
|
+
source_kinds: &[&str],
|
|
1722
|
+
source_values: &[&str],
|
|
1723
|
+
output_field_types: &[&str],
|
|
1724
|
+
) -> ParsedProjectionPlan {
|
|
1725
|
+
ParsedProjectionPlan {
|
|
1726
|
+
document_variant_type: None,
|
|
1727
|
+
document_variant_value: None,
|
|
1728
|
+
output_variant_type: None,
|
|
1729
|
+
output_variant_value: None,
|
|
1730
|
+
document_field_names: Vec::new(),
|
|
1731
|
+
document_field_types: Vec::new(),
|
|
1732
|
+
output_field_types: output_field_types.iter().map(|s| s.to_string()).collect(),
|
|
1733
|
+
source_kinds: source_kinds.iter().map(|s| s.to_string()).collect(),
|
|
1734
|
+
source_values: source_values.iter().map(|s| s.to_string()).collect(),
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
#[test]
|
|
1739
|
+
fn plain_put_payload_reports_typed_errors() {
|
|
1740
|
+
let error = plain_put_document_bytes_from_payload(&[0, 3]).unwrap_err();
|
|
1741
|
+
assert_eq!(error, BackboneError::PlainPutPayloadTooShort);
|
|
1742
|
+
assert_eq!(error.to_string(), "Plain put payload is too short");
|
|
1743
|
+
|
|
1744
|
+
let error = plain_put_document_bytes_from_payload(&[1, 3, 0, 0, 0, 0]).unwrap_err();
|
|
1745
|
+
assert_eq!(error, BackboneError::Expected("native plain put payload"));
|
|
1746
|
+
assert_eq!(error.to_string(), "Expected native plain put payload");
|
|
1747
|
+
|
|
1748
|
+
let error = plain_put_document_bytes_from_payload(&[0, 3, 2, 0, 0, 0, 9]).unwrap_err();
|
|
1749
|
+
assert_eq!(error, BackboneError::PlainPutPayloadLengthMismatch);
|
|
1750
|
+
assert_eq!(error.to_string(), "Plain put payload length mismatch");
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1753
|
+
#[test]
|
|
1754
|
+
fn document_signer_fact_decode_reports_typed_errors() {
|
|
1755
|
+
let fact = DocumentPreviousSignerFact {
|
|
1756
|
+
head: "head".to_string(),
|
|
1757
|
+
public_key: vec![1, 2, 3],
|
|
1758
|
+
};
|
|
1759
|
+
let encoded = encode_document_signer_fact(&fact);
|
|
1760
|
+
let decoded = decode_document_signer_fact(&encoded).unwrap();
|
|
1761
|
+
assert_eq!(decoded.head, fact.head);
|
|
1762
|
+
assert_eq!(decoded.public_key, fact.public_key);
|
|
1763
|
+
|
|
1764
|
+
let mut trailing = encoded.clone();
|
|
1765
|
+
trailing.push(0);
|
|
1766
|
+
let error = match decode_document_signer_fact(&trailing) {
|
|
1767
|
+
Ok(_) => panic!("expected trailing-bytes error"),
|
|
1768
|
+
Err(error) => error,
|
|
1769
|
+
};
|
|
1770
|
+
assert_eq!(error, BackboneError::TrailingDocumentSignerFactBytes);
|
|
1771
|
+
assert_eq!(error.to_string(), "Trailing document signer fact bytes");
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
#[test]
|
|
1775
|
+
fn projection_plan_length_mismatch_renders_historical_string() {
|
|
1776
|
+
assert_eq!(
|
|
1777
|
+
BackboneError::ProjectionPlanLengthMismatch.to_string(),
|
|
1778
|
+
"Projection plan length mismatch"
|
|
1779
|
+
);
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
#[test]
|
|
1783
|
+
fn query_decode_errors_forward_the_indexer_string_verbatim() {
|
|
1784
|
+
// decode_query/decode_sort have no typed core error; the document
|
|
1785
|
+
// query/count/sum boundaries forward their String verbatim through
|
|
1786
|
+
// BackboneError::Message. Assert the rendered message is byte-for-byte
|
|
1787
|
+
// the string the indexer core produced (matching the old js_error
|
|
1788
|
+
// funnel that also built Message(error.to_string())).
|
|
1789
|
+
let raw = decode_query(&[0xff]).unwrap_err();
|
|
1790
|
+
assert_eq!(BackboneError::Message(raw.clone()).to_string(), raw);
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
#[test]
|
|
1794
|
+
fn projected_document_fields_report_typed_errors() {
|
|
1795
|
+
let error =
|
|
1796
|
+
read_projected_document_fields(&[], None, None, &["a".to_string()], &[]).unwrap_err();
|
|
1797
|
+
assert_eq!(error, BackboneError::DocumentProjectionPlanLengthMismatch);
|
|
1798
|
+
assert_eq!(
|
|
1799
|
+
error.to_string(),
|
|
1800
|
+
"Document projection plan length mismatch"
|
|
1801
|
+
);
|
|
1802
|
+
|
|
1803
|
+
let error =
|
|
1804
|
+
read_projected_document_fields(&[], Some("u16"), Some("1"), &[], &[]).unwrap_err();
|
|
1805
|
+
assert_eq!(error, BackboneError::UnsupportedDocumentVariantType);
|
|
1806
|
+
assert_eq!(error.to_string(), "Unsupported document variant type");
|
|
1807
|
+
|
|
1808
|
+
let error = read_projected_document_fields(&[], Some("u8"), None, &[], &[]).unwrap_err();
|
|
1809
|
+
assert_eq!(error, BackboneError::MissingDocumentVariant);
|
|
1810
|
+
assert_eq!(error.to_string(), "Missing document variant");
|
|
1811
|
+
|
|
1812
|
+
let error =
|
|
1813
|
+
read_projected_document_fields(&[], Some("u8"), Some("abc"), &[], &[]).unwrap_err();
|
|
1814
|
+
assert_eq!(error, BackboneError::InvalidDocumentVariant);
|
|
1815
|
+
assert_eq!(error.to_string(), "Invalid document variant");
|
|
1816
|
+
|
|
1817
|
+
let error =
|
|
1818
|
+
read_projected_document_fields(&[], Some("u8"), Some("1"), &[], &[]).unwrap_err();
|
|
1819
|
+
assert_eq!(error, BackboneError::Truncated("document variant"));
|
|
1820
|
+
assert_eq!(error.to_string(), "Truncated document variant");
|
|
1821
|
+
|
|
1822
|
+
let error =
|
|
1823
|
+
read_projected_document_fields(&[0], Some("u8"), Some("1"), &[], &[]).unwrap_err();
|
|
1824
|
+
assert_eq!(error, BackboneError::DocumentVariantMismatch);
|
|
1825
|
+
assert_eq!(error.to_string(), "Document variant mismatch");
|
|
1826
|
+
}
|
|
1827
|
+
|
|
1828
|
+
#[test]
|
|
1829
|
+
fn projection_variant_and_value_writers_report_typed_errors() {
|
|
1830
|
+
let mut out = Vec::new();
|
|
1831
|
+
let error = write_projection_variant(&mut out, Some("u8"), None).unwrap_err();
|
|
1832
|
+
assert_eq!(error, BackboneError::MissingOutputVariant);
|
|
1833
|
+
assert_eq!(error.to_string(), "Missing output variant");
|
|
1834
|
+
|
|
1835
|
+
let error = write_projection_variant(&mut out, Some("u8"), Some("abc")).unwrap_err();
|
|
1836
|
+
assert_eq!(error, BackboneError::InvalidOutputVariant);
|
|
1837
|
+
assert_eq!(error.to_string(), "Invalid output variant");
|
|
1838
|
+
|
|
1839
|
+
let error = write_projection_variant(&mut out, Some("u16"), Some("1")).unwrap_err();
|
|
1840
|
+
assert_eq!(error, BackboneError::UnsupportedOutputVariantType);
|
|
1841
|
+
assert_eq!(error.to_string(), "Unsupported output variant type");
|
|
1842
|
+
|
|
1843
|
+
let error = write_projection_value(&mut out, "string", &ProjectionValue::None).unwrap_err();
|
|
1844
|
+
assert_eq!(error, BackboneError::ProjectionValueOutputTypeMismatch);
|
|
1845
|
+
assert_eq!(
|
|
1846
|
+
error.to_string(),
|
|
1847
|
+
"Projection value does not match output type"
|
|
1848
|
+
);
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
#[test]
|
|
1852
|
+
fn projection_value_readers_report_typed_errors() {
|
|
1853
|
+
let mut offset = 0usize;
|
|
1854
|
+
let error = read_projection_value(&[2], &mut offset, "bool").unwrap_err();
|
|
1855
|
+
assert_eq!(error, BackboneError::InvalidBool("projection bool"));
|
|
1856
|
+
assert_eq!(error.to_string(), "Invalid bool projection bool");
|
|
1857
|
+
|
|
1858
|
+
let mut offset = 0usize;
|
|
1859
|
+
let error = read_projection_value(&[2], &mut offset, "option:u8").unwrap_err();
|
|
1860
|
+
assert_eq!(error, BackboneError::InvalidProjectionOptionMarker);
|
|
1861
|
+
assert_eq!(error.to_string(), "Invalid projection option marker");
|
|
1862
|
+
|
|
1863
|
+
let mut offset = 0usize;
|
|
1864
|
+
let error = read_projection_value(&[], &mut offset, "u128").unwrap_err();
|
|
1865
|
+
assert_eq!(error, BackboneError::UnsupportedProjectedDocumentFieldType);
|
|
1866
|
+
assert_eq!(
|
|
1867
|
+
error.to_string(),
|
|
1868
|
+
"Unsupported projected document field type"
|
|
1869
|
+
);
|
|
1870
|
+
|
|
1871
|
+
let mut offset = 0usize;
|
|
1872
|
+
let error = skip_projection_value(&[], &mut offset, "u128").unwrap_err();
|
|
1873
|
+
assert_eq!(error, BackboneError::UnsupportedDocumentProjectionFieldType);
|
|
1874
|
+
assert_eq!(
|
|
1875
|
+
error.to_string(),
|
|
1876
|
+
"Unsupported document projection field type"
|
|
1877
|
+
);
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
#[test]
|
|
1881
|
+
fn projection_sources_report_typed_errors() {
|
|
1882
|
+
let plan = projection_plan(&["context"], &["bogus"], &["u64"]);
|
|
1883
|
+
let error =
|
|
1884
|
+
project_document_index_simple_bytes_with_plan(&[], &plan, 0, 0, "h", "g", 0, None)
|
|
1885
|
+
.unwrap_err();
|
|
1886
|
+
assert_eq!(error, BackboneError::UnsupportedContextProjectionSource);
|
|
1887
|
+
assert_eq!(error.to_string(), "Unsupported context projection source");
|
|
1888
|
+
|
|
1889
|
+
let plan = projection_plan(&["bogus"], &["x"], &["u64"]);
|
|
1890
|
+
let error =
|
|
1891
|
+
project_document_index_simple_bytes_with_plan(&[], &plan, 0, 0, "h", "g", 0, None)
|
|
1892
|
+
.unwrap_err();
|
|
1893
|
+
assert_eq!(error, BackboneError::UnsupportedProjectionSourceKind);
|
|
1894
|
+
assert_eq!(error.to_string(), "Unsupported projection source kind");
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1897
|
+
#[test]
|
|
1898
|
+
fn document_context_field_variants_render_exact_messages() {
|
|
1899
|
+
for label in ["created", "modified", "head", "gid", "size"] {
|
|
1900
|
+
assert_eq!(
|
|
1901
|
+
BackboneError::MissingDocumentContextField(label).to_string(),
|
|
1902
|
+
format!("Missing document context {label} field")
|
|
1903
|
+
);
|
|
1904
|
+
}
|
|
1905
|
+
assert_eq!(
|
|
1906
|
+
BackboneError::MissingDocumentContextField("created").to_string(),
|
|
1907
|
+
"Missing document context created field"
|
|
1908
|
+
);
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1911
|
+
#[test]
|
|
1912
|
+
fn document_index_put_chain_variants_render_exact_messages() {
|
|
1913
|
+
for (error, message) in [
|
|
1914
|
+
(
|
|
1915
|
+
BackboneError::DocumentContextSuffixCapacityOverflow,
|
|
1916
|
+
"Document context suffix capacity overflow",
|
|
1917
|
+
),
|
|
1918
|
+
(
|
|
1919
|
+
BackboneError::DocumentSchemaIrNotConfigured,
|
|
1920
|
+
"Native backbone document schema IR has not been configured",
|
|
1921
|
+
),
|
|
1922
|
+
(
|
|
1923
|
+
BackboneError::MissingCachedDocumentProjectionPlan,
|
|
1924
|
+
"Missing cached document projection plan",
|
|
1925
|
+
),
|
|
1926
|
+
(
|
|
1927
|
+
BackboneError::MissingPlainPutPayloadForDocumentIndex,
|
|
1928
|
+
"Missing plain put payload for document index",
|
|
1929
|
+
),
|
|
1930
|
+
(
|
|
1931
|
+
BackboneError::MissingPlainPutPayloadForDocumentProjection,
|
|
1932
|
+
"Missing plain put payload for document projection",
|
|
1933
|
+
),
|
|
1934
|
+
] {
|
|
1935
|
+
assert_eq!(error.to_string(), message);
|
|
1936
|
+
}
|
|
1937
|
+
}
|
|
1938
|
+
}
|