Skip to content

Generate the object layer from the catalog's object model - #26

Merged
estebanzimanyi merged 2 commits into
MobilityDB:mainfrom
estebanzimanyi:feat/generate-the-object-layer-from-the-model
Sep 3, 2026
Merged

Generate the object layer from the catalog's object model#26
estebanzimanyi merged 2 commits into
MobilityDB:mainfrom
estebanzimanyi:feat/generate-the-object-layer-from-the-model

Conversation

@estebanzimanyi

Copy link
Copy Markdown
Member

GoMEOS ships a generated flat FFI layer and a hand-written idiomatic one, so
every class, method and conversion above the wrappers is written and maintained
by hand. The catalog already states that layer: objectModel.lattice carries the
temporal tree, companions the Box, Collection and Value hierarchies, and
classes.<Class>.methods assigns each public MEOS function to the class it is a
method of, under its canonical camelCase ooName. MEOS.NET projects the same
model through its own tools/objectgen.py; this is the Go projection of it.

Go spells inheritance as embedding, so TBool embeds TAlpha embeds Temporal
and a parent's methods are promoted. Each instance carries the MEOS pointer, and
the two packages exchange it as an unsafe.Pointer, because cgo types are
package-scoped and *C.Temporal in functions is not the same Go type as one
declared here.

THE SIGNATURES COME FROM codegen.SIGNATURES, so the two generators cannot
disagree. MEOS declares bool tbool_value_at_timestamptz(..., bool *value) --
four parameters, one of them written through -- while the wrapper takes three and
answers two values. Reading the C signature would reconstruct a shape the wrapper
does not have. The table is filled by RUNNING the flat generator, so which
functions have a wrapper is decided in one place and this file holds no second
copy of what that generator skips.

ABSENCE STAYS AN OPTIONAL, in the shape this repository already merged: where
MEOS answers a flag and writes the value out, the method answers
(value, ok, error) with ok false leaving the value at its zero and the error
nil. TBool.ValueAtTimestamptz is generated to exactly what #21 hand-wrote.

MEASURED against a catalog derived at current master: 115 classes, 1256 methods,
105 deferred, each deferral naming the parameter or result that stopped it rather
than being dropped silently. go build ./types ./functions and go vet ./types
both exit 0, gofmt -l reports 0 of 116 files, and a second run of the generator
reproduces the tree byte for byte.

The layer is ADDITIVE: the root package is untouched, so no published name moves.

Stacked on #25 (the snapshot refresh), which the generated layer calls into: types/geometry.go uses functions.GeomArea and functions.GeomAzimuth, which the pre-refresh snapshot does not declare.

Regenerating from a catalog derived at current master moves two wrappers, both
of them MEOS's own movement rather than a generator change:

  * `tbigint_values` takes `int *` where the snapshot recorded `int32_t *`, so
    the cast becomes `(*C.int)`;
  * `geom_azimuth` joins the geo surface, and it carries a folded out-parameter,
    so the wrapper answers `(bool, float64, error)`.

The committed snapshot is what CI compiles before it regenerates, so it has to
be the projection of the surface that exists today rather than of the one that
existed when it was last written.
GoMEOS ships a generated flat FFI layer and a hand-written idiomatic one, so
every class, method and conversion above the wrappers is written and maintained
by hand. The catalog already states that layer: `objectModel.lattice` carries the
temporal tree, `companions` the Box, Collection and Value hierarchies, and
`classes.<Class>.methods` assigns each public MEOS function to the class it is a
method of, under its canonical camelCase `ooName`. MEOS.NET projects the same
model through its own `tools/objectgen.py`; this is the Go projection of it.

Go spells inheritance as embedding, so `TBool` embeds `TAlpha` embeds `Temporal`
and a parent's methods are promoted. Each instance carries the MEOS pointer, and
the two packages exchange it as an `unsafe.Pointer`, because cgo types are
package-scoped and `*C.Temporal` in `functions` is not the same Go type as one
declared here.

THE SIGNATURES COME FROM `codegen.SIGNATURES`, so the two generators cannot
disagree. MEOS declares `bool tbool_value_at_timestamptz(..., bool *value)` --
four parameters, one of them written through -- while the wrapper takes three and
answers two values. Reading the C signature would reconstruct a shape the wrapper
does not have. The table is filled by RUNNING the flat generator, so which
functions have a wrapper is decided in one place and this file holds no second
copy of what that generator skips.

ABSENCE STAYS AN OPTIONAL, in the shape this repository already merged: where
MEOS answers a flag and writes the value out, the method answers
`(value, ok, error)` with `ok` false leaving the value at its zero and the error
nil. `TBool.ValueAtTimestamptz` is generated to exactly what MobilityDB#21 hand-wrote.

MEASURED against a catalog derived at current master: 115 classes, 1256 methods,
105 deferred, each deferral naming the parameter or result that stopped it rather
than being dropped silently. `go build ./types ./functions` and `go vet ./types`
both exit 0, `gofmt -l` reports 0 of 116 files, and a second run of the generator
reproduces the tree byte for byte.

The layer is ADDITIVE: the root package is untouched, so no published name moves.
@estebanzimanyi
estebanzimanyi merged commit c704c36 into MobilityDB:main Sep 3, 2026
2 checks passed
@estebanzimanyi
estebanzimanyi deleted the feat/generate-the-object-layer-from-the-model branch September 3, 2026 16:45
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.

1 participant