Source code for httk.store.served_specs
"""Derive OPTIMADE property names and types from the storage schema IR.
This module deliberately depends only on the neutral schema representation and
httk-core definitions. SQL and Mongo layers can therefore share the same
property derivation without importing one another's backend.
"""
from collections.abc import Mapping
from typing import Any, Final, cast
from httk.core import PropertyDefinition
from httk.store.db.schema import FieldSpec, TableSchema
__all__ = ["definition_fulltype", "served_specs"]
_SCALAR_FULLTYPES: Final[dict[str, str]] = {
"str": "string",
"int": "integer",
"bool": "boolean",
"float": "float",
}
_CODEC_FULLTYPES: Final[dict[str, str]] = {
"float": "float",
"fraction": "float",
"fracscalar": "float",
"surdscalar": "float",
"datetime": "timestamp",
}
def _fulltype_of(spec: FieldSpec) -> str | None:
"""Return the served OPTIMADE fulltype for one schema field, if any."""
if spec.role == "scalar":
return _SCALAR_FULLTYPES.get(spec.columns[0].kind)
if spec.role == "encoded":
assert spec.codec_name is not None
return _CODEC_FULLTYPES.get(spec.codec_name)
if spec.role == "fixed_array":
return "list of list of float"
if spec.role == "child":
if spec.shape is not None:
return "list of list of float"
if spec.target is not None:
return None
if spec.codec_name is not None:
element = _CODEC_FULLTYPES.get(spec.codec_name)
else:
element = _SCALAR_FULLTYPES.get(spec.child.element_columns[0].kind) if spec.child is not None else None
return None if element is None else f"list of {element}"
return None
[docs]
def served_specs(schema: TableSchema, prefix: str) -> list[tuple[str, FieldSpec, str]]:
"""Return the served ``(name, field spec, fulltype)`` triples.
:param schema: The resolved schema whose fields are inspected.
:param prefix: The registered prefix used for served property names.
:return: One triple for every schema field with an OPTIMADE value type.
"""
served: list[tuple[str, FieldSpec, str]] = []
for spec in schema.fields:
fulltype = _fulltype_of(spec)
if fulltype is not None:
served.append((f"{prefix}custom_{spec.field}", spec, fulltype))
return served
def _fulltype_from_doc(doc: Mapping[str, Any]) -> str:
optimade_type = doc["x-optimade-type"]
if optimade_type == "list":
return "list of " + _fulltype_from_doc(doc["items"])
if optimade_type == "dictionary":
return "dict"
return cast(str, optimade_type)
[docs]
def definition_fulltype(definition: PropertyDefinition) -> str:
"""Return the OPTIMADE fulltype declared by a property definition.
:param definition: The property definition to inspect.
:return: Its scalar, list, or dictionary fulltype string.
"""
return _fulltype_from_doc(definition.as_optimade())