Context
#201 changed PersistenceBackend::query from a prefix-glob contract to the
MQTT-style grammar subscriptions already use: * covers exactly one
dot-separated segment, # covers zero or more. The implementation and the
CHANGELOGs landed with the PR; the documentation and tests that teach the old
grammar did not.
Raised in review as
thread 23,
where it was agreed as non-blocking for that PR but required before release —
the affected files are published crate documentation for a grammar that now
fails silently. This issue is what that thread is waiting on.
Line references are as of b790143.
The problem is the record keys, not just the patterns
The obvious read is "replace ::* with .#". That is not sufficient, and doing
only that would leave the examples incoherent.
Every persistence example keys its records with :: as the separator —
accuracy::vienna, my_record::key, sensor::a. A wildcard must be its own
whole dot-separated segment, so accuracy::vienna is a single segment and no
pattern can partition that key space at all. accuracy::* is likewise one
segment containing a literal *, so it is a literal key that matches nothing:
// aimdb-persistence/src/pattern.rs:66
fn a_wildcard_must_be_its_own_segment() {
assert_eq!(literal_prefix("sensors*"), "sensors*");
aimdb-persistence-sqlite/CHANGELOG.md:20 already records the consequence
("Patterns over keys that are not dot-separated ("temp::*") no longer
wildcard") — but every example still uses exactly such keys.
So the sweep is: migrate the example keys to dot-separated, then fix the
patterns over them. A reader who copies today's README gets a query that
returns zero rows and no error.
The sections below are commit-sized. §1–§3 are pure documentation; §4 is the
test change and is the only one that can fail CI.
1. aimdb-persistence/README.md
Keys:
:17 — .persist("my_record::key") in the API table.
:67-71 — configure::<Accuracy>("accuracy::vienna") / ("accuracy::berlin")
and their matching reg.persist(...) calls.
:137-138 — configure::<MyRecord>("my_record::key") + reg.persist(...).
:140 — the commented-out format!("my_record::{}", city).
Patterns over them:
:77 — query_latest("accuracy::*", 10), captioned "Latest 10 per city".
:153, :162, :167, :182 — "my_record::*" across query_latest,
query_range, query_raw and the error-handling example.
:152 — the prose "pattern supports * wildcard", which now needs to name
both wildcards and say they are whole segments.
With keys migrated to accuracy.vienna / accuracy.berlin, the right pattern at
:77 is accuracy.*, not accuracy.# — both keys are exactly one segment
below accuracy, and * says so. Reserve # for the cases where depth varies;
query_raw at :167 is the one that feeds the AimX record.query handler, so
# is the honest choice there (see remote::QUERY_ALL_PATTERN). Worth one line
of prose contrasting the two, since choosing between them is the thing the old
grammar never made anyone think about.
2. aimdb-persistence-sqlite/README.md
Same treatment, smaller surface: :54-55 (configure + persist on
accuracy::vienna) and :60 (query_latest("accuracy::*", 5)).
Do not touch CHANGELOG.md:20 — its "temp::*" is a historical entry
describing the break, and is correct as written.
3. Rustdoc
aimdb-persistence/src/query_ext.rs:19-21 — query_latest's "Pattern
support: "accuracy::*" returns latest N from each matching record. Single
record: "accuracy::vienna"". Both halves are wrong now: the first matches
nothing, and the second is no longer contrastive since it is just a
wildcard-free pattern. query_range and query_raw below it say "pattern"
without defining it and can point at the canonical statement instead of
restating it.
aimdb-persistence/src/backend.rs:19 — StoredValue::record_name's example
value is "accuracy::vienna". This is the type the backend contract is
written against, so the stale key sits directly beside the corrected grammar.
backend.rs:52-61 (PersistenceBackend::query) and pattern.rs are already
correct and are the wording the rest should defer to. Nothing to change there.
4. aimdb-persistence/tests/query_skip_invalid.rs
Keys at :100, :105, :110, :115, :163, :168, :173, :199, :204,
:258, :279, :284, :289; patterns at :133, :182, :213, :237,
:266, :298; the doc table at :91-96.
These tests pass today and would keep passing after a careless key rename,
which is the actual gap the review named:
// :50 — Returns all pre-configured rows unconditionally (params ignored).
fn query<'a>(&'a self, _record_pattern: &'a str, _params: QueryParams)
MockBackend::query ignores the pattern entirely, so no test in the crate proves
a pattern ever reaches a backend, let alone that it is interpreted under the new
grammar. The six tests here exercise the filter_map in AimDbQueryExt and are
right to keep that focus — but the mock should honor record_pattern via the
re-exported topic_matches so the suite stops being blind to the grammar, and
one case should pin the behavior that motivated the change: a sensor.* query
must not return sensor.deep.nested.
aimdb-persistence-sqlite has real coverage of this against SQLite
(src/lib.rs:266 filters rows through topic_matches); what is missing is
coverage at the backend-contract level, which is where a third-party backend
author would look.
5. Out of scope — but confirm before closing
:: keys also appear in examples/remote-access-demo/src/server.rs:136-181 and
aimdb-wasm-adapter/tests/transform_join_integration_tests.rs:42-48. Neither is
broken: the demo never persists and subscribes to one exact key
(client.rs:179), and exact-match lookup is unaffected by the grammar. They are
only unwildcardable, which nothing there tries to do.
Leaving them is defensible. Changing them is also defensible, as the ::
convention is what led the persistence docs into this in the first place. Make it
an explicit decision rather than an oversight, and if they stay, they should not
be cited anywhere as examples of a pattern-friendly key.
Acceptance criteria
grep -rn '::\*' aimdb-persistence/ aimdb-persistence-sqlite/ returns only
CHANGELOG.md entries.
- No persistence example, rustdoc or test registers a record key that a
wildcard cannot address — i.e. no :: in any key that an accompanying
pattern is meant to match.
MockBackend::query in query_skip_invalid.rs honors record_pattern
through topic_matches, and a regression asserts sensor.* excludes
sensor.deep.nested.
- Prose that mentions patterns names both
* (exactly one segment) and #
(zero or more) and states that a wildcard is a whole segment; the
crate-level statement stays in backend.rs with others referring to it
rather than restating it.
make check green.
Context
#201 changed
PersistenceBackend::queryfrom a prefix-glob contract to theMQTT-style grammar subscriptions already use:
*covers exactly onedot-separated segment,
#covers zero or more. The implementation and theCHANGELOGs landed with the PR; the documentation and tests that teach the old
grammar did not.
Raised in review as
thread 23,
where it was agreed as non-blocking for that PR but required before release —
the affected files are published crate documentation for a grammar that now
fails silently. This issue is what that thread is waiting on.
Line references are as of
b790143.The problem is the record keys, not just the patterns
The obvious read is "replace
::*with.#". That is not sufficient, and doingonly that would leave the examples incoherent.
Every persistence example keys its records with
::as the separator —accuracy::vienna,my_record::key,sensor::a. A wildcard must be its ownwhole dot-separated segment, so
accuracy::viennais a single segment and nopattern can partition that key space at all.
accuracy::*is likewise onesegment containing a literal
*, so it is a literal key that matches nothing:aimdb-persistence-sqlite/CHANGELOG.md:20already records the consequence("Patterns over keys that are not dot-separated (
"temp::*") no longerwildcard") — but every example still uses exactly such keys.
So the sweep is: migrate the example keys to dot-separated, then fix the
patterns over them. A reader who copies today's README gets a query that
returns zero rows and no error.
The sections below are commit-sized. §1–§3 are pure documentation; §4 is the
test change and is the only one that can fail CI.
1.
aimdb-persistence/README.mdKeys:
:17—.persist("my_record::key")in the API table.:67-71—configure::<Accuracy>("accuracy::vienna")/("accuracy::berlin")and their matching
reg.persist(...)calls.:137-138—configure::<MyRecord>("my_record::key")+reg.persist(...).:140— the commented-outformat!("my_record::{}", city).Patterns over them:
:77—query_latest("accuracy::*", 10), captioned "Latest 10 per city".:153,:162,:167,:182—"my_record::*"acrossquery_latest,query_range,query_rawand the error-handling example.:152— the prose "pattern supports*wildcard", which now needs to nameboth wildcards and say they are whole segments.
With keys migrated to
accuracy.vienna/accuracy.berlin, the right pattern at:77isaccuracy.*, notaccuracy.#— both keys are exactly one segmentbelow
accuracy, and*says so. Reserve#for the cases where depth varies;query_rawat:167is the one that feeds the AimXrecord.queryhandler, so#is the honest choice there (seeremote::QUERY_ALL_PATTERN). Worth one lineof prose contrasting the two, since choosing between them is the thing the old
grammar never made anyone think about.
2.
aimdb-persistence-sqlite/README.mdSame treatment, smaller surface:
:54-55(configure+persistonaccuracy::vienna) and:60(query_latest("accuracy::*", 5)).Do not touch
CHANGELOG.md:20— its"temp::*"is a historical entrydescribing the break, and is correct as written.
3. Rustdoc
aimdb-persistence/src/query_ext.rs:19-21—query_latest's "Patternsupport:
"accuracy::*"returns latest N from each matching record. Singlerecord:
"accuracy::vienna"". Both halves are wrong now: the first matchesnothing, and the second is no longer contrastive since it is just a
wildcard-free pattern.
query_rangeandquery_rawbelow it say "pattern"without defining it and can point at the canonical statement instead of
restating it.
aimdb-persistence/src/backend.rs:19—StoredValue::record_name's examplevalue is
"accuracy::vienna". This is the type the backend contract iswritten against, so the stale key sits directly beside the corrected grammar.
backend.rs:52-61(PersistenceBackend::query) andpattern.rsare alreadycorrect and are the wording the rest should defer to. Nothing to change there.
4.
aimdb-persistence/tests/query_skip_invalid.rsKeys at
:100,:105,:110,:115,:163,:168,:173,:199,:204,:258,:279,:284,:289; patterns at:133,:182,:213,:237,:266,:298; the doc table at:91-96.These tests pass today and would keep passing after a careless key rename,
which is the actual gap the review named:
MockBackend::queryignores the pattern entirely, so no test in the crate provesa pattern ever reaches a backend, let alone that it is interpreted under the new
grammar. The six tests here exercise the
filter_mapinAimDbQueryExtand areright to keep that focus — but the mock should honor
record_patternvia there-exported
topic_matchesso the suite stops being blind to the grammar, andone case should pin the behavior that motivated the change: a
sensor.*querymust not return
sensor.deep.nested.aimdb-persistence-sqlitehas real coverage of this against SQLite(
src/lib.rs:266filters rows throughtopic_matches); what is missing iscoverage at the backend-contract level, which is where a third-party backend
author would look.
5. Out of scope — but confirm before closing
::keys also appear inexamples/remote-access-demo/src/server.rs:136-181andaimdb-wasm-adapter/tests/transform_join_integration_tests.rs:42-48. Neither isbroken: the demo never persists and subscribes to one exact key
(
client.rs:179), and exact-match lookup is unaffected by the grammar. They areonly unwildcardable, which nothing there tries to do.
Leaving them is defensible. Changing them is also defensible, as the
::convention is what led the persistence docs into this in the first place. Make it
an explicit decision rather than an oversight, and if they stay, they should not
be cited anywhere as examples of a pattern-friendly key.
Acceptance criteria
grep -rn '::\*' aimdb-persistence/ aimdb-persistence-sqlite/returns onlyCHANGELOG.mdentries.wildcard cannot address — i.e. no
::in any key that an accompanyingpattern is meant to match.
MockBackend::queryinquery_skip_invalid.rshonorsrecord_patternthrough
topic_matches, and a regression assertssensor.*excludessensor.deep.nested.*(exactly one segment) and#(zero or more) and states that a wildcard is a whole segment; the
crate-level statement stays in
backend.rswith others referring to itrather than restating it.
make checkgreen.