Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,9 @@ bare-name mapping that MobilityDB now registers natively (PR #1075). The
pipeline folds it into the catalog as `portableAliases` (with `byOperator`
/ `byBareName` lookups), so **every binding/engine generates the identical
bare names** and a user learns one reference and assumes the rest. A
position operator has one name per class instead (`setLeft` … `stboxLeft`),
which the catalog derives from the `@sqlfn` tags as `positionNames`.
position or a topological operator has one name per class instead
(`setLeft` … `stboxLeft`, `setOverlaps` … `stboxOverlaps`), which the catalog
derives from the `@sqlfn` tags as `positionNames`.

It is curated canonical data, kept verbatim (only bijective lookups are
derived — no C-symbol guessing; upstream aliases reuse each operator's own
Expand Down
14 changes: 7 additions & 7 deletions docs/cross-repo-handoff.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ python tools/portable_parity.py # -> output/meos-portable-parity.json (bare-nam

| Artifact | Contents |
|---|---|
| `meos-idl.json#/portableAliases` | canonical operator→bare-name dialect: `byOperator`, `byBareName`, `families`, `explicitBacking`, `scope`; the position operators' names by class: `positionFamilies`, `byPositionOperator`, `positionNames` (operator → class → SQL name) |
| `meos-idl.json#/portableAliases` | canonical operator→bare-name dialect: `byOperator`, `byBareName`, `families`, `explicitBacking`, `scope`; the position and topological operators' names by class: `positionFamilies`, `byPositionOperator`, `positionNames` (operator → class → SQL name) |
| `meos-idl.json#/functions[].{network,wire,api}` | per-function projectability + decode/encode/array/out-param wire model |
| `meos-idl.json#/temporalTypes` | per `Temporal<T>`: its `base`, its `bbox`, the `mfjson` type token `asMFJSON` writes, and the `number` / `spatial` / `linear` classes |
| `meos-idl.json#/typeRelations/byBase` | each base type's `set`, `span`, `spanset` and its `temporal` types, the last a list since a base carries several |
Expand All @@ -28,12 +28,12 @@ python tools/portable_parity.py # -> output/meos-portable-parity.json (bare-nam
## What each consumer produces

**MobilityDuck, MobilitySpark** — register the **exact bare names** from
`portableAliases.byOperator` (drop type-qualified forms like
`spanOverlaps`). Done = every operator in `byOperator` is callable by its
bare name, parity-checked with the same prefix logic as
`portable_parity.py`, **0 unbacked**. A position operator registers its
names by class from `portableAliases.positionNames` (`stboxLeft`,
`tboxBefore`), which are the `sqlfn` of its functions.
`portableAliases.byOperator`. Done = every operator in `byOperator` is
callable by its bare name, parity-checked with the same prefix logic as
`portable_parity.py`, **0 unbacked**. A position or a topological operator
registers its names by class from `portableAliases.positionNames`
(`stboxLeft`, `tboxBefore`, `spanOverlaps`, `stboxContains`), which are the
`sqlfn` of its functions.

**PyMEOS, JMEOS, MEOS.NET** — code-generate from `meos-idl.json`
(`functions` + `portableAliases`) so every binding emits **identical** bare
Expand Down
48 changes: 27 additions & 21 deletions docs/portable-aliases.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,38 +16,41 @@ family, and is **type-agnostic** (it applies to every temporal type):

| Family | Operator → bare name |
|---|---|
| Topology | `&&`→`overlaps` `@>`→`contains` `<@`→`contained` `-\|-`→`adjacent` |
| Temporal comparison | `#=`→`tEqual` `#<>`→`tNotEqual` `#<`→`tLessThan` `#<=`→`tLessEqual` `#>`→`tGreaterThan` `#>=`→`tGreaterEqual` |
| Ever comparison | `?=`→`eEqual` `?<>`→`eNotEqual` `?<`→`eLessThan` `?<=`→`eLessEqual` `?>`→`eGreaterThan` `?>=`→`eGreaterEqual` |
| Always comparison | `%=`→`aEqual` `%<>`→`aNotEqual` `%<`→`aLessThan` `%<=`→`aLessEqual` `%>`→`aGreaterThan` `%>=`→`aGreaterEqual` |
| Distance | `<->`→`tDistance` `\|=\|`→`nearestApproachDistance` |
| Same | `~=`→`same` |

25 operator→bare-name pairs. Already-canonical (no aliasing needed):
21 operator→bare-name pairs. Already-canonical (no aliasing needed):
`eIntersects`, `atTime`, restriction and spatial-relationship functions.

## Position operators
## Position and topological operators

A position operator has one name per class of its operands instead: the
class followed by the position, a temporal operand taking the class of its
bounding box (MobilityDB#2717). `<<` is `setLeft`, `spanLeft`,
`spansetLeft`, `tboxLeft`, `stboxLeft` and `tpcboxLeft`; the Y and Z
positions exist for `stbox` and `tpcbox`. The mapping holds each operator
with its position, the stem those names and the MEOS C functions share
(`left_set_set`, `left_tspatial_tspatial`), under `positionFamilies`:
A position or a topological operator has one name per class of its operands
instead: the class followed by the stem, a temporal operand taking the class
of its bounding box. `<<` is `setLeft`, `spanLeft`, `spansetLeft`,
`tboxLeft`, `stboxLeft` and `tpcboxLeft` (MobilityDB#2717); the Y and Z
positions exist for `stbox` and `tpcbox`. `&&` is `setOverlaps`,
`spanOverlaps`, `spansetOverlaps`, `tboxOverlaps`, `stboxOverlaps` and
`tpcboxOverlaps` (MobilityDB#2930). The mapping holds each operator with its
stem, which those names and the MEOS C functions share (`left_set_set`,
`overlaps_tspatial_tspatial`), under `positionFamilies`, where the key
`position` names the stem:

| Family | Operator → position |
| Family | Operator → stem |
|---|---|
| Topology | `&&`→`overlaps` `@>`→`contains` `<@`→`contained` `-\|-`→`adjacent` |
| Time position | `<<#`→`before` `#>>`→`after` `&<#`→`overbefore` `#&>`→`overafter` |
| Space X | `<<`→`left` `>>`→`right` `&<`→`overleft` `&>`→`overright` |
| Space Y | `<<\|`→`below` `\|>>`→`above` `&<\|`→`overbelow` `\|&>`→`overabove` |
| Space Z | `<</`→`front` `/>>`→`back` `&</`→`overfront` `/&>`→`overback` |

The catalog derives the names by class from the `@sqlfn` tags of the
functions whose `@sqlop` is the operator (`positionNames`, 64 names for the
16 operators). A name that is not the class followed by the position, or an
operator that no function carries, stops the pipeline: either means the
tags and the mapping disagree.
functions whose `@sqlop` is the operator (`positionNames`, 88 names for the
20 operators over MobilityDB `96d665686e`). A name that is not the class
followed by the stem, or an operator that no function carries, stops the
pipeline: either means the tags and the mapping disagree.

## In the catalog

Expand All @@ -56,12 +59,14 @@ plus derived lookups for codegen:

```json
"portableAliases": {
"byOperator": { "&&": "overlaps", "#=": "tEqual", "~=": "same", ... },
"byBareName": { "overlaps": "&&", "tEqual": "#=", "same": "~=", ... },
"byOperator": { "#=": "tEqual", "<->": "tDistance", "~=": "same", ... },
"byBareName": { "tEqual": "#=", "tDistance": "<->", "same": "~=", ... },
"bareNames": ["aEqual", "aGreaterEqual", ..., "tLessEqual", "tLessThan", "tNotEqual"],
"count": 25,
"byPositionOperator": { "<<": "left", "<<#": "before", ... },
"count": 21,
"byPositionOperator": { "&&": "overlaps", "<<": "left", "<<#": "before", ... },
"positionNames": {
"&&": { "set": "setOverlaps", "span": "spanOverlaps", "spanset": "spansetOverlaps",
"stbox": "stboxOverlaps", "tbox": "tboxOverlaps", "tpcbox": "tpcboxOverlaps" },
"<<": { "set": "setLeft", "span": "spanLeft", "spanset": "spansetLeft",
"stbox": "stboxLeft", "tbox": "tboxLeft", "tpcbox": "tpcboxLeft" },
"<<|": { "stbox": "stboxBelow", "tpcbox": "tpcboxBelow" }, ...
Expand Down Expand Up @@ -94,8 +99,9 @@ end state.
`portable_parity.py` is the meos-api.json analogue of MobilityDB's
`tools/portable_aliases/generate.py --check`: it cross-references every
bare name against the catalog's function families (by the MEOS bare-name
prefix convention), and every position operator against the family its
position prefixes (`left_*`, `before_*`) with its SQL names by class, and
prefix convention), and every position or topological operator against the
family its stem prefixes (`left_*`, `before_*`, `overlaps_*`) with its SQL
names by class, and
writes `output/meos-portable-parity.json`. A bare name whose C family
prefix differs is backed by the functions whose `@sqlfn` is the bare name
(`tEqual` by the `teq_*` family, `eEqual` by `ever_eq_*`, `tDistance` by
Expand Down
30 changes: 9 additions & 21 deletions meta/portable-aliases.json
Original file line number Diff line number Diff line change
@@ -1,30 +1,12 @@
{
"_comment": "Canonical portable bare-name dialect \u2014 the single codegen source of truth (RFC #920). Every binding/engine generates the SAME bare names from this mapping so users learn one reference and assume the rest. Operators are SQL operator symbols; bareName is the portable function name. The mapping is type-agnostic: it applies to EVERY temporal type family. A position operator (`positionFamilies`) has instead one name per class of its operands.",
"_comment": "Canonical portable bare-name dialect \u2014 the single codegen source of truth (RFC #920). Every binding/engine generates the SAME bare names from this mapping so users learn one reference and assume the rest. Operators are SQL operator symbols; bareName is the portable function name. The mapping is type-agnostic: it applies to EVERY temporal type family. An operator of `positionFamilies`, a position or a topological operator, has instead one name per class of its operands.",
"provenance": {
"discussion": "MobilityDB#861",
"rfc": "MobilityDB RFC #920 (doc/rfc/sql-portability/README.md, branch rfc/sql-portability)",
"nativePR": "MobilityDB#1075 (1303 operator-overload aliases, each reusing the operator's own C symbol \u2014 identical by construction; CI-gated by tools/portable_aliases/generate.py --check)",
"manualChapter": "MobilityDB#1078"
},
"families": {
"topology": [
{
"operator": "&&",
"bareName": "overlaps"
},
{
"operator": "@>",
"bareName": "contains"
},
{
"operator": "<@",
"bareName": "contained"
},
{
"operator": "-|-",
"bareName": "adjacent"
}
],
"temporalComparison": [
{ "operator": "#=", "bareName": "tEqual" },
{ "operator": "#<>", "bareName": "tNotEqual" },
Expand Down Expand Up @@ -66,8 +48,14 @@
}
]
},
"_positionFamiliesComment": "A position operator has one SQL name per class of its operands, the class followed by the position: `<<` is setLeft, spanLeft, spansetLeft, tboxLeft, stboxLeft and tpcboxLeft (MobilityDB#2717). A temporal operand takes the class of its bounding box. `position` is the stem those names and the MEOS C functions share (left_set_set, left_tspatial_tspatial). The catalog derives the names by class from the @sqlfn tags of the functions whose @sqlop is the operator (`portableAliases.positionNames`).",
"_positionFamiliesComment": "A position or a topological operator has one SQL name per class of its operands, the class followed by the stem: `<<` is setLeft, spanLeft, spansetLeft, tboxLeft, stboxLeft and tpcboxLeft (MobilityDB#2717), `&&` is setOverlaps, spanOverlaps, tboxOverlaps, stboxOverlaps and tpcboxOverlaps (MobilityDB#2930). A temporal operand takes the class of its bounding box. `position` is the stem those names and the MEOS C functions share (left_set_set, overlaps_tspatial_tspatial). The catalog derives the names by class from the @sqlfn tags of the functions whose @sqlop is the operator (`portableAliases.positionNames`).",
"positionFamilies": {
"topology": [
{ "operator": "&&", "position": "overlaps" },
{ "operator": "@>", "position": "contains" },
{ "operator": "<@", "position": "contained" },
{ "operator": "-|-", "position": "adjacent" }
],
"timePosition": [
{ "operator": "<<#", "position": "before" },
{ "operator": "#>>", "position": "after" },
Expand Down Expand Up @@ -125,6 +113,6 @@
"notes": [
"Generate aliases by reusing each operator's own backing C function (equivalence by construction), never by reimplementing; mirror MobilityDB tools/portable_aliases/generate.py + its 100%-coverage audit.",
"User-facing API uses the full name `trgeometry`; internal functions keep the `trgeo_` prefix \u2014 do NOT normalize the internal prefix.",
"Goal: 100% parity ecosystem-wide \u2014 every operator has its portable name (its bare name, or its name by class for a position operator) on every engine, no gaps, no headline exclusions."
"Goal: 100% parity ecosystem-wide \u2014 every operator has its portable name (its bare name, or its name by class for a position or topological operator) on every engine, no gaps, no headline exclusions."
]
}
2 changes: 1 addition & 1 deletion meta/portable-aliases.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@

"positionFamilies": {
"type": "object",
"description": "Position operators, whose SQL names are the class of their operands followed by the position (setLeft … stboxLeft). `position` is the stem the names and the MEOS C functions share; the catalog derives the names by class.",
"description": "Position and topological operators, whose SQL names are the class of their operands followed by the stem (setLeft … stboxLeft, setOverlaps … stboxOverlaps). `position` is the stem the names and the MEOS C functions share; the catalog derives the names by class.",
"minProperties": 1,
"additionalProperties": {
"type": "array",
Expand Down
65 changes: 35 additions & 30 deletions parser/portable.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
`meta/portable-aliases.json` is the curated, authoritative operator →
bare-name mapping (RFC #920; native in MobilityDB via PR #1075). Folding it
into the catalog means every binding/engine generates the *identical* bare
names, so a user learns one reference and assumes the rest. A position
operator has one name per class instead (setLeft … stboxLeft), derived from
the catalog's @sqlfn/@sqlop tags by ``attach_position_names``.
names, so a user learns one reference and assumes the rest. A position or a
topological operator has one name per class instead (setLeft … stboxLeft,
setOverlaps … stboxOverlaps), derived from the catalog's @sqlfn/@sqlop tags by
``attach_position_names``.

This is curated canonical data, not a heuristic — it is preserved verbatim
and only *derived* lookups are added (no guessing of C symbols: upstream
Expand All @@ -32,9 +33,9 @@ def attach_portable_aliases(idl: dict, path: Path) -> dict:
if len(by_operator) != len(pairs) or len(by_bare_name) != len(pairs):
raise ValueError("portable-aliases: duplicate operator or bareName")

# A position operator has one SQL name per class of its operands (setLeft …
# stboxLeft), so it has no bare name: it is absent from the families above, and
# its operator and position are each unique.
# A position or a topological operator has one SQL name per class of its operands
# (setLeft … stboxLeft, setOverlaps … stboxOverlaps), so it has no bare name: it is
# absent from the families above, and its operator and stem are each unique.
positions = [p for fam in data["positionFamilies"].values() for p in fam]
by_position_operator = {p["operator"]: p["position"] for p in positions}
if (len(by_position_operator) != len(positions)
Expand All @@ -50,26 +51,28 @@ def attach_portable_aliases(idl: dict, path: Path) -> dict:
"explicitBacking": data.get("explicitBacking", {}),
"scope": data["scope"], # cbuffer/npoint/pose/rgeo in scope
"notes": data["notes"],
"byOperator": by_operator, # "&&" -> "overlaps"
"byBareName": by_bare_name, # "overlaps" -> "&&"
"byOperator": by_operator, # "#=" -> "tEqual"
"byBareName": by_bare_name, # "tEqual" -> "#="
"bareNames": sorted(by_bare_name),
"count": len(pairs),
"byPositionOperator": by_position_operator, # "<<" -> "left"
"byPositionOperator": by_position_operator, # "<<" -> "left", "&&" -> "overlaps"
}
return idl


def attach_position_names(idl: dict) -> dict:
"""Derive the SQL names of each position operator, by class.

A position operator has one SQL name per class of its operands, the class
followed by the position: ``<<`` is setLeft, spanLeft, spansetLeft, tboxLeft,
stboxLeft and tpcboxLeft (MobilityDB#2717), a temporal operand taking the class of
its bounding box. The names are the ``@sqlfn`` tags of the functions whose
``@sqlop`` is the operator, and the class is the name less its position. Adds
``portableAliases.positionNames``: operator -> class -> SQL name.

A name that does not end with its operator's position, or an operator that no
"""Derive the SQL names of each position or topological operator, by class.

A position or a topological operator has one SQL name per class of its operands,
the class followed by the stem: ``<<`` is setLeft, spanLeft, spansetLeft, tboxLeft,
stboxLeft and tpcboxLeft (MobilityDB#2717), ``&&`` is setOverlaps, spanOverlaps,
spansetOverlaps, tboxOverlaps, stboxOverlaps and tpcboxOverlaps (MobilityDB#2930),
a temporal operand taking the class of its bounding box. The names are the
``@sqlfn`` tags of the functions whose ``@sqlop`` is the operator, and the class is
the name less its stem. Adds ``portableAliases.positionNames``: operator -> class
-> SQL name.

A name that does not end with its operator's stem, or an operator that no
function carries, raises: either means the @sqlfn/@sqlop tags and the mapping
disagree, which a binding would otherwise inherit silently.

Expand Down Expand Up @@ -103,20 +106,22 @@ def attach_position_names(idl: dict) -> dict:


def classify_backing_sqlfn(idl: dict) -> dict:
"""Mark the bounding-box topological BACKING ``@sqlfn`` tags.

MobilityDB backs the five topological operators (~=/@>/<@/-|-/&&) with a SHARED C
``@sqlfn`` tag named ``<op>_bbox`` (same_bbox, contains_bbox, contained_bbox,
overlaps_bbox, adjacent_bbox). That tag is NEVER emitted as a ``CREATE FUNCTION`` —
the deployed, user-facing SQL name is the operator's bare portable alias
(same/contains/…). The raw ``sqlfn`` is therefore a backing name, not a public one;
a binding that registers it leaks a function MobilityDB does not expose. Flag those
"""Mark the shared bounding-box BACKING ``@sqlfn`` tags of a bare name.

A function behind an operator with a bare name (``~=``, ``same``) may carry a
SHARED C ``@sqlfn`` tag named ``<op>_bbox`` (same_bbox). That tag is NEVER emitted
as a ``CREATE FUNCTION`` — the deployed, user-facing SQL name is the operator's bare
portable alias. The raw ``sqlfn`` is therefore a backing name, not a public one; a
binding that registers it leaks a function MobilityDB does not expose. Flag those
records with ``sqlfnBackingOnly`` + the ``publicSqlName`` (the bare alias) so every
binding uniformly registers the bare name + operator and drops the ``_bbox`` tag.
binding uniformly registers the bare name + operator and drops the ``_bbox`` tag. A
topological operator (``&&``, ``@>``, ``<@``, ``-|-``) has names by class
(MobilityDB#2930): its ``@sqlfn`` tags are its public names, and a ``_bbox`` tag on
it is refused by #attach_position_names.

Not a heuristic: grounded in two catalog-native facts — the ``_bbox`` shared-backing
convention AND the operator→bareName map. ``publicSqlName`` is always defined because
every ``_bbox`` sqlfn carries one of the five topological operators.
convention AND the operator→bareName map. ``publicSqlName`` is defined for every
record flagged, since only an operator of that map is flagged.

MUST run AFTER ``attach_sqlfn_map`` (sqlfn/sqlop) AND ``attach_portable_aliases``
(byOperator) — it reads all three.
Expand Down
Loading
Loading