Skip to content

Introduce context-first configuration and register Unitsdb model classes#25

Merged
ronaldtse merged 10 commits intomainfrom
feat/context-register-models
Apr 22, 2026
Merged

Introduce context-first configuration and register Unitsdb model classes#25
ronaldtse merged 10 commits intomainfrom
feat/context-register-models

Conversation

@suleman-uzair
Copy link
Copy Markdown
Member

Summary

This change introduces a context-first Unitsdb::Configuration flow and wires model registration through Configuration.register_model.

What changed

  • Added Unitsdb::Configuration with:
    • register_model
    • context / populate_context
    • register / populate_register
    • substitution resolution for symbol/class substitution input
  • Updated Unitsdb.database to be context-aware and cache by context ID.
  • Updated Unitsdb::Database.from_db to:
    • accept context:
    • load within GlobalContext.with_context(context_id)
    • pass register: only when an explicit register exists
  • Added Configuration.register_model(...) entries across Unitsdb model files, including:
    • core serializable models
    • identifier/reference/root-derived models
    • QUDT and UCUM model classes
  • Added focused context support spec:
    • validates custom context substitution path with explicit register population

Current behavior/design intent

  • Context is first-class.
  • Register remains explicit (not auto-created).
  • No self-healing/stale auto-refresh logic.

@suleman-uzair suleman-uzair requested a review from Copilot April 20, 2026 13:20
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Introduces a context-first configuration system for Unitsdb and registers model classes through Unitsdb::Configuration, while updating database loading to be context-aware and more strictly validated.

Changes:

  • Added Unitsdb::Configuration for model registration, context creation, and substitution resolution.
  • Refactored Unitsdb::Database.from_db to validate/compose YAML inputs and to load within a GlobalContext context.
  • Updated Unitsdb model files to self-register via Configuration.register_model, and added specs for context usage and improved load behavior.

Reviewed changes

Copilot reviewed 35 out of 35 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
spec/unitsdb/database_spec.rb Adds specs for stdout silence and clearer load-time failure cases (invalid YAML structure, missing collection key).
spec/unitsdb/configuration_spec.rb Adds a focused spec validating custom context + substitution + explicit registration behavior.
lib/unitsdb/units.rb Registers Units model in the configuration registry.
lib/unitsdb/unit_systems.rb Registers UnitSystems model in the configuration registry.
lib/unitsdb/unit_system_reference.rb Registers UnitSystemReference model in the configuration registry.
lib/unitsdb/unit_system.rb Registers UnitSystem model in the configuration registry.
lib/unitsdb/unit_reference.rb Registers UnitReference model in the configuration registry.
lib/unitsdb/unit.rb Registers Unit model in the configuration registry.
lib/unitsdb/ucum.rb Registers UCUM-related models in the configuration registry.
lib/unitsdb/symbol_presentations.rb Registers SymbolPresentations model in the configuration registry.
lib/unitsdb/si_derived_base.rb Registers SiDerivedBase model in the configuration registry.
lib/unitsdb/scales.rb Registers Scales model in the configuration registry.
lib/unitsdb/scale_reference.rb Registers ScaleReference model in the configuration registry.
lib/unitsdb/scale_properties.rb Registers ScaleProperties model in the configuration registry.
lib/unitsdb/scale.rb Registers Scale model in the configuration registry.
lib/unitsdb/root_unit_reference.rb Registers RootUnitReference model in the configuration registry.
lib/unitsdb/qudt.rb Registers QUDT-related models in the configuration registry.
lib/unitsdb/quantity_reference.rb Registers QuantityReference model in the configuration registry.
lib/unitsdb/quantity.rb Registers Quantity model in the configuration registry.
lib/unitsdb/quantities.rb Registers Quantities model in the configuration registry.
lib/unitsdb/prefixes.rb Registers Prefixes model in the configuration registry.
lib/unitsdb/prefix_reference.rb Registers PrefixReference model in the configuration registry.
lib/unitsdb/prefix.rb Registers Prefix model in the configuration registry.
lib/unitsdb/localized_string.rb Registers LocalizedString model in the configuration registry.
lib/unitsdb/identifier.rb Registers Identifier model in the configuration registry.
lib/unitsdb/external_reference.rb Registers ExternalReference model in the configuration registry.
lib/unitsdb/dimensions.rb Registers Dimensions model in the configuration registry.
lib/unitsdb/dimension_reference.rb Registers DimensionReference model in the configuration registry.
lib/unitsdb/dimension_details.rb Registers DimensionDetails model in the configuration registry.
lib/unitsdb/dimension.rb Registers Dimension model in the configuration registry.
lib/unitsdb/database.rb Refactors DB loading: centralizes file list, validates schema versions/collections, improves error handling, adds context-based load wrapper, registers Database.
lib/unitsdb/configuration.rb Adds the new configuration/context system including registry building and substitution resolution.
lib/unitsdb/config.rb Removes legacy Unitsdb::Config model lookup mechanism.
lib/unitsdb.rb Requires configuration, adjusts autoloads for Opal, makes Unitsdb.database context-aware with per-context caching.
Gemfile Points lutaml-model to a specific GitHub branch for global-context behavior changes.
Comments suppressed due to low confidence (1)

spec/unitsdb/database_spec.rb:1

  • ENV["DEBUG"] = original_debug will raise a TypeError when original_debug is nil (common when DEBUG was not set). Restore the env var by deleting it when original_debug is nil, otherwise reassign it.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/unitsdb/database.rb
Comment on lines +325 to 327
Lutaml::Model::GlobalContext.with_context(context_id) do
from_hash(combined_hash, register: context_id)
end
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description says register: should be passed “only when an explicit register exists”, but this call passes register: context_id unconditionally. If the intent is to avoid implicitly creating/using a register, update this to only provide register: when a register has been explicitly populated/declared for that context (and omit the keyword entirely otherwise).

Copilot uses AI. Check for mistakes.
Comment thread lib/unitsdb/database.rb
Comment on lines +361 to +382
def self.validate_schema_versions!(documents)
versions = DATABASE_FILES.each_with_object({}) do |(collection_key, filename), result|
document = documents.fetch(collection_key)
result[filename] = document.fetch("schema_version")
rescue KeyError
raise Errors::DatabaseFileInvalidError,
"Missing schema_version in files: #{missing_schema.join(', ')}"
"Missing schema_version in #{filename}"
end

# Extract versions from each file
prefixes_version = prefixes_hash["schema_version"]
dimensions_version = dimensions_hash["schema_version"]
units_version = units_hash["schema_version"]
quantities_version = quantities_hash["schema_version"]
unit_systems_version = unit_systems_hash["schema_version"]

# Check if all versions match
versions = [
prefixes_version,
dimensions_version,
units_version,
quantities_version,
unit_systems_version,
]

unless versions.uniq.size == 1
version_info = {
"prefixes.yaml" => prefixes_version,
"dimensions.yaml" => dimensions_version,
"units.yaml" => units_version,
"quantities.yaml" => quantities_version,
"unit_systems.yaml" => unit_systems_version,
}
unless versions.values.uniq.size == 1
raise Errors::VersionMismatchError,
"Version mismatch in database files: #{version_info.inspect}"
"Version mismatch in database files: #{versions.inspect}"
end

# Check if the version is supported
version = versions.first
unless version == "2.0.0"
version = versions.values.first
unless version == SUPPORTED_SCHEMA_VERSION
raise Errors::UnsupportedVersionError,
"Unsupported database version: #{version}. Only version 2.0.0 is supported."
"Unsupported database version: #{version}. Only version #{SUPPORTED_SCHEMA_VERSION} is supported."
end

combined_yaml = {
"schema_version" => prefixes_version,
"prefixes" => prefixes_hash["prefixes"],
"dimensions" => dimensions_hash["dimensions"],
"units" => units_hash["units"],
"quantities" => quantities_hash["quantities"],
"unit_systems" => unit_systems_hash["unit_systems"],
}.to_yaml
version
end
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This introduces new, user-facing validation paths (missing schema_version, version mismatch across files, and unsupported schema version) without corresponding specs. Add tests in spec/unitsdb/database_spec.rb that exercise each raised error and verify the error class/message match expectations (similar to the newly added “not a mapping” and “missing collection key” specs).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

@ronaldtse ronaldtse Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@suleman-uzair this seems to require a revert? Or is this because of Opal? The point is to check all of the schema files to ensure they have the same version.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ronaldtse I do not think this needs a revert. I refactored the structure here, but I did not intend to change the version validation or the other existing behavior in this method. If you had a specific case in mind that looks different after the refactor, let me know and I'll look into it.

Comment thread lib/unitsdb/configuration.rb Outdated
end

def context(id = context_id, force_populate: false)
return find_context(id) if find_context(id) && !force_populate && populated_for(id)
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

find_context(id) is called twice, which is unnecessary and makes the early-return condition harder to read. Store it in a local variable (e.g., existing = find_context(id)) and use that for the conditional/return to reduce repeated lookups and improve clarity.

Suggested change
return find_context(id) if find_context(id) && !force_populate && populated_for(id)
existing = find_context(id)
return existing if existing && !force_populate && populated_for(id)

Copilot uses AI. Check for mistakes.
@suleman-uzair suleman-uzair changed the title [WIP] Introduce context-first configuration and register Unitsdb model classes Introduce context-first configuration and register Unitsdb model classes Apr 22, 2026
@suleman-uzair suleman-uzair marked this pull request as ready for review April 22, 2026 08:20
@ronaldtse ronaldtse merged commit 21b5bf7 into main Apr 22, 2026
15 of 18 checks passed
@ronaldtse ronaldtse deleted the feat/context-register-models branch April 22, 2026 10:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants