Units CLI

QUDT Units CLI

The S2DM Units CLI provides integration with the QUDT (Quantities, Units, Dimensions and Types) reference model to generate standardized GraphQL unit enums. This replaces static unit definitions with a dynamic system that synchronizes directly from the authoritative QUDT repository.

How QUDT Maps to GraphQL

The sync command reads a specific released version of QUDT and maps it onto GraphQL SDL enum structures:

  • Each QUDT quantity kind (e.g. quantitykind:Velocity) becomes one GraphQL enum type (e.g. VelocityUnit).
  • Each QUDT unit belonging to that quantity kind (e.g. unit:M-PER-SEC) becomes one enum value of that type (e.g. M_PER_SEC).

Elements that are marked deprecated in the QUDT release — whether the unit itself or its quantity kind — are intentionally not mapped and are ignored. They do not appear in generated enums in any form (not even as @deprecated values); only QUDT’s current, non-deprecated vocabulary is represented.

Features

  • Dynamic Unit Synchronization: Fetch unit definitions from QUDT’s GitHub repository
  • Version Management: Support for specific QUDT versions with automatic latest version detection
  • Semantic References: Generated enums include @reference directives linking to QUDT IRIs with version tags
  • UCUM Integration: Includes UCUM codes in descriptive comments for standardization
  • SDL Validation: Generated GraphQL enums are validated for correctness
  • Automatic Cleanup: Removes stale files before sync to ensure fresh state

Commands

s2dm units sync

Synchronizes unit definitions from the QUDT repository and generates GraphQL enum files in the S2DM_HOME directory (~/.s2dm/units/qudt).

Unit files are downloaded to ~/.s2dm/units/qudt to prevent users from modifying them. This is a temporary solution. In the future, QUDT unit GraphQL files will be moved to a separate repository and referenced/downloaded from there.

Syntax:

s2dm units sync [--version <version>] [--dry-run]

Examples:

# Sync latest version
s2dm units sync

# Sync specific version
s2dm units sync --version v3.1.5

# Check what would be generated without creating files
s2dm units sync --dry-run

Options:

  • --version (optional): QUDT release tag, including the leading v (e.g. v3.1.6). This must match a git tag in the qudt-public-repo exactly. Defaults to the latest release tag if not specified
  • --dry-run (optional): Show how many enum files would be generated without creating them

Output:

  • Creates <QuantityKind>Unit.graphql files in ~/.s2dm/units/qudt (e.g., LengthUnit.graphql)
  • Generates README.md with version and attribution information
  • Generates CHANGELOG.md listing quantity kinds and units that QUDT marks as deprecated in that release (and are therefore intentionally excluded from the generated enums)
  • Reports number of enum files generated

s2dm units check-version

Compares the local synced QUDT version with the latest available version. By default, checks the ~/.s2dm/units/qudt directory.

Syntax:

s2dm units check-version

Output:

  • ✓ Units are up to date. if current version matches latest
  • ⚠ There is a newer release available: X.Y.Z if update is needed

Generated Enum Format

Each generated enum follows this structure:

# Generated by S2DM from the QUDT unit vocabulary. See README.md in this directory for the QUDT version used.
# Source data: QUDT Public Repository (https://github.com/qudt/qudt-public-repo)
# © QUDT.org — Licensed under Creative Commons Attribution 4.0 International (CC BY 4.0)
# License: https://creativecommons.org/licenses/by/4.0/
# Changes: vocabulary terms transformed to GraphQL SDL enum format by S2DM (https://github.com/COVESA/s2dm)
enum LengthUnit @reference(uri: "http://qudt.org/vocab/quantitykind/Length") {
  """Meter | UCUM: m"""
  M @reference(uri: "http://qudt.org/vocab/unit/M")

  """Kilometer | UCUM: km"""
  KILOM @reference(uri: "http://qudt.org/vocab/unit/KiloM")

  """Centimeter | UCUM: cm"""
  CENTIM @reference(uri: "http://qudt.org/vocab/unit/CentiM")
  ...
}

The QUDT catalog version is not embedded in each enum file. It is recorded once in the directory’s README.md so that re-syncing an unchanged catalog doesn’t touch every file, keeping Git diffs focused on actual content changes.

Key Elements:

  • Enum name: <QuantityKind>Unit in PascalCase
  • @reference on enum: Links to QUDT quantity kind IRI
  • @reference on values: Links to QUDT unit IRI
  • Triple-quote docstrings: Include human-readable label and UCUM code
  • Value names: Use QUDT URI segments converted to SCREAMING_SNAKE_CASE

Directory Structure

QUDT units are stored in the S2DM_HOME directory:

~/.s2dm/units/qudt/                   # QUDT units (generated, read-only)
├── README.md                         # Version and attribution
├── CHANGELOG.md                      # Deprecated quantity kinds/units excluded from this release
├── LengthUnit.graphql                # Length units
├── VelocityUnit.graphql              # Velocity units
└── ... (500+ more unit enums)

If you need custom units specific to your domain, create them in your project directory:

units/custom/                         # Custom units (manual, in your project)
├── MyDomainUnit.graphql              # Custom domain units
└── SpecialUnit.graphql               # Special use case units

Workflow Example

  1. Initial Setup: Sync units from QUDT

    s2dm units sync --version v3.1.5

    This downloads unit enums to ~/.s2dm/units/qudt.

  2. Use Units in Schema Development: Reference generated enums

    type Vehicle {
      speed(unit: VelocityUnit = KM_PER_HR): Float
      acceleration(unit: AccelerationUnit = M_PER_SEC2): Float
    }
  3. Check for Updates: Periodically check for new QUDT versions

    s2dm units check-version
  4. Update When Needed: Sync newer versions as they become available

    s2dm units sync --version v3.2.0

Why URI-Based Symbols?

S2DM uses QUDT URI segments instead of labels for enum values because:

  • Consistency: URI segments are standardized and don’t vary across languages
  • Reliability: Labels can be inconsistent, missing, or contain formatting issues
  • Semantic Accuracy: URI segments represent the canonical QUDT identifier

Technical Details

Data Source

  • Repository: qudt/qudt-public-repo
  • File: src/main/rdf/vocab/unit/VOCAB_QUDT-UNITS-ALL.ttl
  • Format: RDF Turtle (TTL)

Deduplication

  • Uses DISTINCT in SPARQL queries to eliminate exact duplicates
  • Filters out units marked qudt:deprecated true to prevent symbol conflicts (e.g. unit:Standard, replaced by unit:STANDARD)
  • Filters out units whose quantity kind is itself marked qudt:deprecated true (e.g. quantitykind:Conductivity, replaced by quantitykind:ElectricConductivity), so units aren’t grouped under a stale quantity kind label
  • Prefers entries with UCUM codes when duplicates remain

QUDT’s own git tags are prefixed with v (e.g. v3.5.2), not bare version numbers. Always pass --version with the v prefix, matching the tag names at qudt-public-repo/tags.

Error Handling

  • Network Issues: Graceful failure with informative error messages
  • Invalid Units: Units that cannot generate valid symbols are skipped
  • SDL Validation: Generated GraphQL enums are validated for correctness
  • Version Check: Safe handling of GitHub API rate limits