[M3] mxaccess-galaxy: GalaxyTagMetadata + parser + Resolver trait + SQL

Lands M3 stream A — the pure-Rust foundation of the Galaxy resolver:
the data type, the tag-reference parser, the async trait, and the
canonical SQL strings. Unblocks F13 (NmxClient::write_* wrappers depend
on GalaxyTagMetadata) without pulling in tiberius yet.

New
- metadata.rs (~195 LoC, 7 tests) — GalaxyTagMetadata record (port of
  cs:6-73). Includes is_buffer_property + to_reference_handle(galaxy_id)
  bridging into mxaccess-codec::MxReferenceHandle::from_names.
- parser.rs (~330 LoC, 12 tests) — ParsedTagReference parser. Handles
  Object.Attribute (1 candidate), Object.Primitive.Attribute (2
  candidates: primitive-attr first, dotted-attr second per cs:181-185),
  and the case-insensitive .property(buffer) suffix. Pure-Rust, no I/O.
- resolver.rs (~200 LoC, 5 tests including a tokio-driven InMemoryResolver
  proving the trait is implementable without SQL) — async Resolver trait
  + ResolverError. Default browse returns Backend("not implemented") so
  read-only backends don't need to override it.
- sql.rs (~280 LoC, 5 smoke tests) — RESOLVE_SQL + BROWSE_SQL constants
  ported byte-for-byte from cs:208-432. Available publicly so any
  backend (the planned tiberius impl, a wwtools/grdb snapshot replay,
  etc.) can grab the canonical query.

Cargo.toml: added mxaccess-codec (path), async-trait, thiserror;
tokio added as dev-dependency for the resolver-trait async tests.

Deliberately deferred to a later iteration:
- The tiberius-backed Resolver impl behind the galaxy-resolver feature.
- ToValueKind / TryGetValueKind / ProjectWriteValue helpers on
  GalaxyTagMetadata (cs:41-72) — these need a MxDataType -> MxValueKind
  lookup that the codec doesn't currently expose; landing them with
  F13's write-helper iteration keeps the iteration coherent.

Test count delta: 397 -> 427 (+30). All four DoD gates green.
Open followups touched: F13 prerequisite (GalaxyTagMetadata) now in
place; F13 itself stays open until the write helpers wire it up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-05-05 08:17:16 -04:00
parent 0c772d273d
commit d84b066c62
7 changed files with 1148 additions and 10 deletions
+32 -10
View File
@@ -1,14 +1,36 @@
//! `mxaccess-galaxy` — Galaxy Repository SQL resolver.
//! `mxaccess-galaxy` — Galaxy Repository tag resolver.
//!
//! M0 stub. The real resolver lands in M3 — see `design/60-roadmap.md`.
//! Replicates the recursive CTE from
//! `src/MxNativeClient/GalaxyRepositoryTagResolver.cs:209-293`
//! (`deployed_package_chain`) against the verified table set
//! `dbo.gobject` / `dbo.instance` / `dbo.dynamic_attribute` /
//! `dbo.attribute_definition` / `dbo.primitive_instance` / `dbo.package`.
//! M3 stream A landed: the trait + metadata + parser + canonical SQL
//! constants. The actual `tiberius`-backed implementation behind the
//! `galaxy-resolver` Cargo feature is a follow-up (see
//! `design/followups.md`).
//!
//! **Resolver input contract**: `tag_name`-form only (e.g. `DelmiaReceiver_001`),
//! not `contained_name`-form (e.g. `TestMachine_001.DelmiaReceiver`). See
//! `wwtools/grdb/README.md` for the asymmetry.
//! Modules:
//!
//! - [`metadata`] — [`metadata::GalaxyTagMetadata`] record (port of
//! `GalaxyTagMetadata` at `GalaxyRepositoryTagResolver.cs:6-73`).
//! - [`parser`] — [`parser::ParsedTagReference`] (port of `cs:167-206`).
//! Pure-Rust, no I/O. Handles `Object.Attribute` /
//! `Object.Primitive.Attribute` / `.property(buffer)` shapes.
//! - [`resolver`] — [`resolver::Resolver`] async trait + [`resolver::ResolverError`].
//! - [`sql`] — `RESOLVE_SQL` + `BROWSE_SQL` constants (the recursive
//! `deployed_package_chain` CTE from `cs:208-432`). Exposed publicly
//! so any backend (the future `tiberius` impl, a snapshot replay
//! harness, etc.) can grab the canonical query.
//!
//! **Resolver input contract**: `tag_name`-form only (e.g.
//! `DelmiaReceiver_001`), not `contained_name`-form (e.g.
//! `TestMachine_001.DelmiaReceiver`). See `wwtools/grdb/README.md` for
//! the asymmetry. The parser does not enforce this — the SQL queries do
//! by joining `g.tag_name = @objectTagName` (not `contained_name`).
#![forbid(unsafe_code)]
pub mod metadata;
pub mod parser;
pub mod resolver;
pub mod sql;
pub use metadata::GalaxyTagMetadata;
pub use parser::{ParseError, ParsedTagReference};
pub use resolver::{Resolver, ResolverError};