create-feltdb 0.8.3 → 0.8.5
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/create.js +25 -21
- package/dist/managed-account.js +11 -0
- package/dist/package-versions.js +1 -1
- package/dist/server-source/Cargo.lock +165 -0
- package/dist/server-source/Cargo.toml +9 -0
- package/dist/server-source/crates/feltdb/Cargo.toml +3 -0
- package/dist/server-source/crates/feltdb/benches/gate13_baseline.rs +44 -44
- package/dist/server-source/crates/feltdb/benches/gate13_phase_7_1_release_economics.rs +12 -24
- package/dist/server-source/crates/feltdb/benches/gate_13_redux.rs +7 -13
- package/dist/server-source/crates/feltdb/benches/gate_13_regression_runner.rs +13 -10
- package/dist/server-source/crates/feltdb/benches/gate_14a_concurrent_writer_scaling.rs +12 -9
- package/dist/server-source/crates/feltdb/benches/gate_14a_production_admission_revalidation.rs +78 -25
- package/dist/server-source/crates/feltdb/benches/gate_14a_rc2_admission_contract.rs +16 -13
- package/dist/server-source/crates/feltdb/benches/gate_14a_rc_root_cause.rs +13 -5
- package/dist/server-source/crates/feltdb/benches/gate_14a_sync1_queued_prototype.rs +41 -22
- package/dist/server-source/crates/feltdb/benches/gate_14a_sync_economics.rs +33 -15
- package/dist/server-source/crates/feltdb/benches/gate_14b_causal_backlog_scaling.rs +100 -33
- package/dist/server-source/crates/feltdb/benches/gate_14c_replication_contract_test.rs +56 -20
- package/dist/server-source/crates/feltdb/benches/gate_14c_replication_scaling.rs +116 -41
- package/dist/server-source/crates/feltdb/benches/gate_14d_combined_dimension_scaling.rs +186 -55
- package/dist/server-source/crates/feltdb/benches/phase_7_1_2_optimization_benchmark.rs +64 -26
- package/dist/server-source/crates/feltdb/benches/phase_7_1_3_crossover_analysis.rs +46 -15
- package/dist/server-source/crates/feltdb/src/admission.rs +8 -15
- package/dist/server-source/crates/feltdb/src/admission_contract_tests.rs +43 -13
- package/dist/server-source/crates/feltdb/src/adversarial_transport.rs +15 -42
- package/dist/server-source/crates/feltdb/src/analytics.rs +65 -19
- package/dist/server-source/crates/feltdb/src/application.rs +113 -30
- package/dist/server-source/crates/feltdb/src/authorization_security_tests.rs +475 -140
- package/dist/server-source/crates/feltdb/src/cardinality_diagnostics.rs +17 -15
- package/dist/server-source/crates/feltdb/src/cardinality_endpoint.rs +0 -1
- package/dist/server-source/crates/feltdb/src/causal_backlog_bound.rs +59 -15
- package/dist/server-source/crates/feltdb/src/causal_dependency_barrier.rs +266 -114
- package/dist/server-source/crates/feltdb/src/causal_dependency_barrier_phase_7_1.rs +25 -7
- package/dist/server-source/crates/feltdb/src/concurrency_fuzzing.rs +10 -15
- package/dist/server-source/crates/feltdb/src/consistency_contract.rs +3 -11
- package/dist/server-source/crates/feltdb/src/crash_atomic_boundary.rs +14 -5
- package/dist/server-source/crates/feltdb/src/crash_injection.rs +21 -25
- package/dist/server-source/crates/feltdb/src/crash_recovery_tests.rs +14 -11
- package/dist/server-source/crates/feltdb/src/dedup_bound_investigation.rs +103 -22
- package/dist/server-source/crates/feltdb/src/distributed_indexing.rs +18 -15
- package/dist/server-source/crates/feltdb/src/durability_guarantees.rs +12 -8
- package/dist/server-source/crates/feltdb/src/durable_dedup_set.rs +1 -5
- package/dist/server-source/crates/feltdb/src/durable_operation_identity.rs +87 -23
- package/dist/server-source/crates/feltdb/src/durable_operation_log.rs +3 -7
- package/dist/server-source/crates/feltdb/src/durable_sync.rs +10 -9
- package/dist/server-source/crates/feltdb/src/equality_index.rs +595 -0
- package/dist/server-source/crates/feltdb/src/in_process_transport.rs +1 -6
- package/dist/server-source/crates/feltdb/src/indexing.rs +35 -38
- package/dist/server-source/crates/feltdb/src/lib.rs +1050 -117
- package/dist/server-source/crates/feltdb/src/managed_cas_tests.rs +4 -1
- package/dist/server-source/crates/feltdb/src/metrics.rs +0 -1
- package/dist/server-source/crates/feltdb/src/multi_node_convergence.rs +1 -2
- package/dist/server-source/crates/feltdb/src/multi_operation_transaction.rs +107 -30
- package/dist/server-source/crates/feltdb/src/observability.rs +19 -6
- package/dist/server-source/crates/feltdb/src/operation_algebra.rs +12 -11
- package/dist/server-source/crates/feltdb/src/operation_log.rs +9 -4
- package/dist/server-source/crates/feltdb/src/p1_application_atomicity.rs +65 -18
- package/dist/server-source/crates/feltdb/src/p1_atomicity_acceptance.rs +193 -57
- package/dist/server-source/crates/feltdb/src/partition_reconciliation.rs +37 -27
- package/dist/server-source/crates/feltdb/src/permutation_scheduler.rs +38 -10
- package/dist/server-source/crates/feltdb/src/persistence_reality.rs +20 -14
- package/dist/server-source/crates/feltdb/src/phase1b_acceptance.rs +394 -229
- package/dist/server-source/crates/feltdb/src/phase1c1_acceptance.rs +8 -6
- package/dist/server-source/crates/feltdb/src/phase1c2_acceptance.rs +11 -13
- package/dist/server-source/crates/feltdb/src/phase1c3_acceptance.rs +90 -72
- package/dist/server-source/crates/feltdb/src/phase1c_atomicity_proof.rs +3 -3
- package/dist/server-source/crates/feltdb/src/phase5_integration.rs +33 -11
- package/dist/server-source/crates/feltdb/src/phase5_scenarios.rs +6 -6
- package/dist/server-source/crates/feltdb/src/phase6_adversarial_scenarios.rs +14 -56
- package/dist/server-source/crates/feltdb/src/phase6_convergence_validator.rs +29 -27
- package/dist/server-source/crates/feltdb/src/phase6_persistence.rs +35 -17
- package/dist/server-source/crates/feltdb/src/phase_1c_real_tcp.rs +8 -2
- package/dist/server-source/crates/feltdb/src/phase_2a_failures.rs +59 -15
- package/dist/server-source/crates/feltdb/src/phase_2b_network.rs +70 -17
- package/dist/server-source/crates/feltdb/src/phase_2c_cascading.rs +23 -6
- package/dist/server-source/crates/feltdb/src/phase_3_durability.rs +12 -3
- package/dist/server-source/crates/feltdb/src/phase_4_baseline.rs +41 -11
- package/dist/server-source/crates/feltdb/src/phase_5_soak.rs +56 -25
- package/dist/server-source/crates/feltdb/src/policy_evaluation.rs +701 -245
- package/dist/server-source/crates/feltdb/src/production_api.rs +31 -13
- package/dist/server-source/crates/feltdb/src/query_execution_diagnostics.rs +126 -0
- package/dist/server-source/crates/feltdb/src/query_performance.rs +6 -8
- package/dist/server-source/crates/feltdb/src/replay_fuzzing.rs +5 -5
- package/dist/server-source/crates/feltdb/src/replica_acknowledgements.rs +48 -18
- package/dist/server-source/crates/feltdb/src/replica_membership.rs +30 -11
- package/dist/server-source/crates/feltdb/src/replication_manager.rs +6 -3
- package/dist/server-source/crates/feltdb/src/replication_protocol.rs +4 -3
- package/dist/server-source/crates/feltdb/src/sharding.rs +36 -10
- package/dist/server-source/crates/feltdb/src/state_conflict_contract.rs +516 -0
- package/dist/server-source/crates/feltdb/src/state_contract.rs +305 -6
- package/dist/server-source/crates/feltdb/src/state_diff_contract.rs +222 -0
- package/dist/server-source/crates/feltdb/src/state_facade.rs +82 -54
- package/dist/server-source/crates/feltdb/src/state_hash.rs +2 -2
- package/dist/server-source/crates/feltdb/src/state_model.rs +1514 -537
- package/dist/server-source/crates/feltdb/src/state_transition_store.rs +6 -3
- package/dist/server-source/crates/feltdb/src/state_trigger.rs +672 -0
- package/dist/server-source/crates/feltdb/src/submission.rs +5 -11
- package/dist/server-source/crates/feltdb/src/sync.rs +12 -0
- package/dist/server-source/crates/feltdb/src/tcp_transport.rs +6 -8
- package/dist/server-source/crates/feltdb/src/transaction_api.rs +24 -35
- package/dist/server-source/crates/feltdb/src/transaction_invariants.rs +24 -8
- package/dist/server-source/crates/feltdb/src/transaction_preconditions.rs +248 -59
- package/dist/server-source/crates/feltdb/src/transactions.rs +17 -20
- package/dist/server-source/crates/feltdb/src/trigger_contract.rs +749 -0
- package/dist/server-source/crates/feltdb/src/worker_mesh.rs +1 -0
- package/dist/server-source/crates/feltdb/src/workload.rs +512 -4
- package/dist/server-source/crates/feltdb/src/workload_diagnostics.rs +442 -0
- package/dist/server-source/crates/feltdb/tests/branching_evidence.rs +299 -0
- package/dist/server-source/crates/feltdb/tests/current_revision_authority_evidence.rs +288 -0
- package/dist/server-source/crates/feltdb/tests/durable_format_compatibility.rs +392 -0
- package/dist/server-source/crates/feltdb/tests/feltdb_state_boundary_tests.rs +436 -220
- package/dist/server-source/crates/feltdb/tests/fixtures/state_conflict_contract_corpus.json +1916 -0
- package/dist/server-source/crates/feltdb/tests/fixtures/state_diff_contract_corpus.json +1878 -0
- package/dist/server-source/crates/feltdb/tests/fixtures/trigger_contract_corpus.json +1862 -0
- package/dist/server-source/crates/feltdb/tests/pr34_query_collection.rs +234 -0
- package/dist/server-source/crates/feltdb/tests/pr35_equality_index.rs +947 -0
- package/dist/server-source/crates/feltdb/tests/pr7_self_authorization_proof.rs +5 -8
- package/dist/server-source/crates/feltdb/tests/pr8_vocabulary_assessment.rs +52 -44
- package/dist/server-source/crates/feltdb/tests/pr9_phase2_boundary_tests.rs +33 -16
- package/dist/server-source/crates/feltdb/tests/pr9_phase3a_path_a_tests.rs +22 -7
- package/dist/server-source/crates/feltdb/tests/pr9_phase3c_authorized_mutations.rs +41 -22
- package/dist/server-source/crates/feltdb/tests/pr9_phase3c_role_based_authorization.rs +25 -8
- package/dist/server-source/crates/feltdb/tests/pr9_phase3c_simple_auth_delete.rs +9 -6
- package/dist/server-source/crates/feltdb/tests/pr9_phase3c_team_delete_role_authorization.rs +120 -69
- package/dist/server-source/crates/feltdb/tests/pr9_teams_role_based_access.rs +21 -10
- package/dist/server-source/crates/feltdb/tests/production_readiness_contract.rs +1032 -0
- package/dist/server-source/crates/feltdb/tests/reconciliation_application.rs +868 -0
- package/dist/server-source/crates/feltdb/tests/reconciliation_wire_format_evidence.rs +221 -0
- package/dist/server-source/crates/feltdb/tests/resource_scoped_revisions.rs +338 -0
- package/dist/server-source/crates/feltdb/tests/revision_identity_contract.rs +1039 -0
- package/dist/server-source/crates/feltdb/tests/revision_model_decision.rs +739 -0
- package/dist/server-source/crates/feltdb/tests/revision_retention_boundary_evidence.rs +427 -0
- package/dist/server-source/crates/feltdb/tests/saas_authorization_integration.rs +3 -3
- package/dist/server-source/crates/feltdb/tests/saas_invitation_lifecycle.rs +25 -22
- package/dist/server-source/crates/feltdb/tests/state_conflict_contract_conformance.rs +1799 -0
- package/dist/server-source/crates/feltdb/tests/state_diff_contract_conformance.rs +1316 -0
- package/dist/server-source/crates/feltdb/tests/state_model_integration.rs +53 -61
- package/dist/server-source/crates/feltdb/tests/state_persistence_integration.rs +156 -61
- package/dist/server-source/crates/feltdb/tests/state_store_boundary_evidence.rs +299 -0
- package/dist/server-source/crates/feltdb/tests/sync_divergence_evidence.rs +255 -0
- package/dist/server-source/crates/feltdb/tests/three_way_input_boundary_evidence.rs +249 -0
- package/dist/server-source/crates/feltdb/tests/trigger_contract_conformance.rs +994 -0
- package/dist/server-source/crates/feltdb-server/src/app_state.rs +2 -1
- package/dist/server-source/crates/feltdb-server/src/audit.rs +1137 -29
- package/dist/server-source/crates/feltdb-server/src/auth.rs +164 -13
- package/dist/server-source/crates/feltdb-server/src/main.rs +800 -34
- package/package.json +1 -1
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
//! PR34 — bounded query execution without collection materialization.
|
|
2
|
+
//!
|
|
3
|
+
//! `FeltDb::query_collection` is the state-access primitive the bounded query
|
|
4
|
+
//! surface executes on. These tests pin the two properties the query path
|
|
5
|
+
//! depends on: it observes every live record of a collection in record-key
|
|
6
|
+
//! order, and it clones only the records its predicate retains.
|
|
7
|
+
|
|
8
|
+
use feltdb::{query_execution_diagnostics, FeltDb, StoredRow};
|
|
9
|
+
use serde_json::json;
|
|
10
|
+
use std::sync::{Mutex, MutexGuard, OnceLock};
|
|
11
|
+
use tempfile::TempDir;
|
|
12
|
+
|
|
13
|
+
/// The read counters are process-global, and the test binary runs its tests in
|
|
14
|
+
/// threads of one process, so a counter assertion is only meaningful while no
|
|
15
|
+
/// other test in this file is reading a collection.
|
|
16
|
+
fn exclusive() -> MutexGuard<'static, ()> {
|
|
17
|
+
static SERIAL: OnceLock<Mutex<()>> = OnceLock::new();
|
|
18
|
+
SERIAL
|
|
19
|
+
.get_or_init(|| Mutex::new(()))
|
|
20
|
+
.lock()
|
|
21
|
+
.unwrap_or_else(|poisoned| poisoned.into_inner())
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
fn seeded(records: usize) -> (TempDir, FeltDb) {
|
|
25
|
+
let directory = TempDir::new().expect("temp dir");
|
|
26
|
+
let db = FeltDb::open(directory.path().join("pr34.log")).expect("open db");
|
|
27
|
+
for index in 0..records {
|
|
28
|
+
db.insert(
|
|
29
|
+
&format!("items:record-{index:05}"),
|
|
30
|
+
json!({ "tenant": format!("tenant-{}", index % 4), "n": index }),
|
|
31
|
+
)
|
|
32
|
+
.expect("insert");
|
|
33
|
+
}
|
|
34
|
+
(directory, db)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
#[test]
|
|
38
|
+
fn scan_returns_only_matching_records() {
|
|
39
|
+
let _serial = exclusive();
|
|
40
|
+
let (_directory, db) = seeded(40);
|
|
41
|
+
|
|
42
|
+
let matches = db
|
|
43
|
+
.query_collection("items", None, |row| {
|
|
44
|
+
row.value.get("tenant") == Some(&json!("tenant-1"))
|
|
45
|
+
})
|
|
46
|
+
.expect("scan");
|
|
47
|
+
|
|
48
|
+
assert_eq!(matches.len(), 10, "one quarter of the collection matches");
|
|
49
|
+
assert!(matches
|
|
50
|
+
.iter()
|
|
51
|
+
.all(|row| row.value.get("tenant") == Some(&json!("tenant-1"))));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
#[test]
|
|
55
|
+
fn scan_of_an_empty_or_unknown_collection_is_empty() {
|
|
56
|
+
let _serial = exclusive();
|
|
57
|
+
let (_directory, db) = seeded(0);
|
|
58
|
+
|
|
59
|
+
assert!(db
|
|
60
|
+
.query_collection("items", None, |_| true)
|
|
61
|
+
.expect("scan")
|
|
62
|
+
.is_empty());
|
|
63
|
+
assert!(db
|
|
64
|
+
.query_collection("no-such-collection", None, |_| true)
|
|
65
|
+
.expect("scan")
|
|
66
|
+
.is_empty());
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
#[test]
|
|
70
|
+
fn scan_visits_records_in_record_key_order() {
|
|
71
|
+
let _serial = exclusive();
|
|
72
|
+
let (_directory, db) = seeded(16);
|
|
73
|
+
|
|
74
|
+
let keys: Vec<String> = db
|
|
75
|
+
.query_collection("items", None, |_| true)
|
|
76
|
+
.expect("scan")
|
|
77
|
+
.iter()
|
|
78
|
+
.map(|row: &StoredRow| row.key.clone())
|
|
79
|
+
.collect();
|
|
80
|
+
let mut sorted = keys.clone();
|
|
81
|
+
sorted.sort();
|
|
82
|
+
|
|
83
|
+
assert_eq!(keys, sorted, "traversal follows the collection's key order");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
#[test]
|
|
87
|
+
fn a_limit_stops_the_traversal_once_it_is_satisfied() {
|
|
88
|
+
let _serial = exclusive();
|
|
89
|
+
let (_directory, db) = seeded(500);
|
|
90
|
+
|
|
91
|
+
let mut visited = 0usize;
|
|
92
|
+
let matches = db
|
|
93
|
+
.query_collection("items", Some(5), |_| {
|
|
94
|
+
visited += 1;
|
|
95
|
+
true
|
|
96
|
+
})
|
|
97
|
+
.expect("scan");
|
|
98
|
+
|
|
99
|
+
assert_eq!(matches.len(), 5, "the limit bounds the result");
|
|
100
|
+
assert_eq!(
|
|
101
|
+
visited, 5,
|
|
102
|
+
"a satisfied limit stops the traversal instead of walking the collection"
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
#[test]
|
|
107
|
+
fn a_scan_clones_only_the_records_it_retains() {
|
|
108
|
+
let _serial = exclusive();
|
|
109
|
+
let (_directory, db) = seeded(2_000);
|
|
110
|
+
|
|
111
|
+
let before = query_execution_diagnostics::counters();
|
|
112
|
+
let matches = db
|
|
113
|
+
.query_collection("items", None, |row| row.value.get("n") == Some(&json!(7)))
|
|
114
|
+
.expect("scan");
|
|
115
|
+
let after = query_execution_diagnostics::counters();
|
|
116
|
+
|
|
117
|
+
assert_eq!(matches.len(), 1);
|
|
118
|
+
assert_eq!(
|
|
119
|
+
after.full_collection_materializations, before.full_collection_materializations,
|
|
120
|
+
"a scan must not fall back to full collection materialization"
|
|
121
|
+
);
|
|
122
|
+
assert_eq!(
|
|
123
|
+
after.scan_records_visited - before.scan_records_visited,
|
|
124
|
+
2_000,
|
|
125
|
+
"the predicate observes every record, borrowed"
|
|
126
|
+
);
|
|
127
|
+
assert_eq!(
|
|
128
|
+
after.scan_records_materialized - before.scan_records_materialized,
|
|
129
|
+
1,
|
|
130
|
+
"only the matching record is cloned"
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
#[test]
|
|
135
|
+
fn full_materialization_is_still_counted_for_readers_that_ask_for_it() {
|
|
136
|
+
let _serial = exclusive();
|
|
137
|
+
let (_directory, db) = seeded(32);
|
|
138
|
+
|
|
139
|
+
let before = query_execution_diagnostics::counters();
|
|
140
|
+
let rows = db.list_collection("items").expect("list");
|
|
141
|
+
let after = query_execution_diagnostics::counters();
|
|
142
|
+
|
|
143
|
+
assert_eq!(rows.len(), 32);
|
|
144
|
+
assert_eq!(
|
|
145
|
+
after.full_collection_materializations - before.full_collection_materializations,
|
|
146
|
+
1
|
|
147
|
+
);
|
|
148
|
+
assert_eq!(
|
|
149
|
+
after.full_collection_records_cloned - before.full_collection_records_cloned,
|
|
150
|
+
32,
|
|
151
|
+
"listing a collection clones every record in it"
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
#[test]
|
|
156
|
+
fn a_scan_result_survives_concurrent_mutation() {
|
|
157
|
+
let _serial = exclusive();
|
|
158
|
+
let (_directory, db) = seeded(200);
|
|
159
|
+
|
|
160
|
+
let matches = db
|
|
161
|
+
.query_collection("items", None, |row| {
|
|
162
|
+
row.value.get("tenant") == Some(&json!("tenant-0"))
|
|
163
|
+
})
|
|
164
|
+
.expect("scan");
|
|
165
|
+
|
|
166
|
+
// The scan returns owned records, so mutation after the lock is released
|
|
167
|
+
// cannot invalidate or rewrite what the caller already holds.
|
|
168
|
+
for index in 0..200 {
|
|
169
|
+
db.delete(&format!("items:record-{index:05}"))
|
|
170
|
+
.expect("delete");
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
assert_eq!(matches.len(), 50);
|
|
174
|
+
assert!(matches
|
|
175
|
+
.iter()
|
|
176
|
+
.all(|row| row.value.get("tenant") == Some(&json!("tenant-0"))));
|
|
177
|
+
assert!(db
|
|
178
|
+
.query_collection("items", None, |_| true)
|
|
179
|
+
.expect("scan")
|
|
180
|
+
.is_empty());
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/// PR35 addition: the indexed execution must not reach the materializing path.
|
|
184
|
+
///
|
|
185
|
+
/// PR34's claim was that a bounded query never enters `list_collection`. PR35
|
|
186
|
+
/// adds a second execution, and an optimization that quietly fell back into a
|
|
187
|
+
/// whole-collection clone would satisfy every correctness test in this
|
|
188
|
+
/// repository while undoing the thing PR34 established. So the property is
|
|
189
|
+
/// re-asserted against the execution that did not exist when it was first
|
|
190
|
+
/// proved: indexed execution materializes nothing, and does not scan either.
|
|
191
|
+
#[test]
|
|
192
|
+
fn an_indexed_query_neither_materializes_nor_scans_the_collection() {
|
|
193
|
+
let _serial = exclusive();
|
|
194
|
+
let (_directory, db) = seeded(400);
|
|
195
|
+
db.create_equality_index("items", "tenant")
|
|
196
|
+
.expect("declare index");
|
|
197
|
+
|
|
198
|
+
let before = query_execution_diagnostics::counters();
|
|
199
|
+
let tenant = json!("tenant-1");
|
|
200
|
+
let matches = db
|
|
201
|
+
.query_collection_by_equality("items", &[("tenant", &tenant)], |row| {
|
|
202
|
+
row.value.get("tenant") == Some(&json!("tenant-1"))
|
|
203
|
+
})
|
|
204
|
+
.expect("indexed query")
|
|
205
|
+
.expect("the field is indexed");
|
|
206
|
+
let after = query_execution_diagnostics::counters();
|
|
207
|
+
|
|
208
|
+
assert_eq!(matches.len(), 100, "one quarter of the collection matches");
|
|
209
|
+
assert_eq!(
|
|
210
|
+
after.full_collection_materializations - before.full_collection_materializations,
|
|
211
|
+
0,
|
|
212
|
+
"indexed execution must not enter the full-collection materialization path",
|
|
213
|
+
);
|
|
214
|
+
assert_eq!(
|
|
215
|
+
after.collection_scans - before.collection_scans,
|
|
216
|
+
0,
|
|
217
|
+
"indexed execution is not a scan",
|
|
218
|
+
);
|
|
219
|
+
assert_eq!(
|
|
220
|
+
after.scan_records_visited - before.scan_records_visited,
|
|
221
|
+
0,
|
|
222
|
+
"and therefore visits no record by traversal",
|
|
223
|
+
);
|
|
224
|
+
assert_eq!(
|
|
225
|
+
after.queries_indexed - before.queries_indexed,
|
|
226
|
+
1,
|
|
227
|
+
"the query is attributed to the indexed execution",
|
|
228
|
+
);
|
|
229
|
+
assert_eq!(
|
|
230
|
+
after.records_predicate_evaluated - before.records_predicate_evaluated,
|
|
231
|
+
100,
|
|
232
|
+
"the predicate runs against the candidate set, not the collection",
|
|
233
|
+
);
|
|
234
|
+
}
|