From 29ca824fd1ef75ed42e7224a679afa2313eeacae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20Zim=C3=A1nyi?= Date: Sun, 11 Oct 2026 13:48:36 +0200 Subject: [PATCH] Give the raster the class its own type carries The object model holds Raster in the Value hierarchy beside Raquet, with the prefix raster and a null temptype, MEOS registering a raster in no enum while every raster function takes one first: raster_copy, raster_mem_size, raster_width, raster_clip and the other raster functions are methods of it, copy, memSize and width among them, and its instances are a Raster *. The floor of .github/workflows/pytest.yml rises to 537, the suite collecting the Raster test of the object model. Witness: against MEOS-API master 4baf117 over MobilityDB master 4eef012a9f raster_copy, raster_mem_size and the 35 other raster functions are unclassified, no-prefix-match, so a binding generating from objectModel.classes declares them as free functions; against this branch they are methods of the class Raster, its cType Raster. Measured over MobilityDB master 4eef012a9f with an all-families libmeos, run.py on upstream 4baf117 and on this branch with the same installed headers: the two catalogs differ in the object model alone, every key of every function, structure and class of typeEncodings being identical; it classifies 37 more functions, all to Raster, leaving 3129 unclassified. The suite collects 537 tests, all passing, none skipped. JMEOS main e8c65dc4 generates byte-identical GeneratedFunctions and object layer, and identical Spark, Spark SQL and Flink SQL surfaces, from both catalogs; its Flink and Kafka facades carry the same 5206 methods, the 37 raster functions in MeosOpsRaster beside the 5 left in MeosOpsFreeRaster. Why: a binding types a raster method and the value it answers from the object model, which holds a class for every value MEOS passes by reference. --- .github/workflows/pytest.yml | 2 +- docs/object-model.md | 2 +- meta/object-model.json | 13 ++++++++++++- tests/test_object_model.py | 16 +++++++++++++++- 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index decb222..1a91a7c 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -96,7 +96,7 @@ jobs: # carries, or a change to them is not exercised until after it merges. # Consumers use the action; this repository owns the rules. - name: Refuse a skip, and a suite that shrank - run: tools/check-test-outcome.py "$RUNNER_TEMP/pytest.log" --min-tests 546 + run: tools/check-test-outcome.py "$RUNNER_TEMP/pytest.log" --min-tests 547 # The rules earn their place by refusing a log that carries what they # name. Both fixtures are written here rather than tracked, and the diff --git a/docs/object-model.md b/docs/object-model.md index 35f8be1..545b843 100644 --- a/docs/object-model.md +++ b/docs/object-model.md @@ -125,7 +125,7 @@ that set from the two predicates and fails until each has a class, so a base type MEOS adds reaches the model with no edit to the file. `Nsegment`, `Raquet` and `JsonPath` are the MeosTypes no membership predicate admits; the model states them, and the same gate states that it -does. `Pcschema`, `RTree`, `RTreeNNCursor`, `SPTree`, `SPNNCursor` and +does. `Pcschema`, `Raster`, `RTree`, `RTreeNNCursor`, `SPTree`, `SPNNCursor` and `MeosArray` go further: MEOS registers them in no enum at all, and they say so with a null `temptype` rather than by leaving the field out. To a binding a pointer to a struct diff --git a/meta/object-model.json b/meta/object-model.json index 4b47a51..6a49f9c 100644 --- a/meta/object-model.json +++ b/meta/object-model.json @@ -381,7 +381,8 @@ "posechain", "pcpoint", "pcpatch", - "raquet" + "raquet", + "raster" ] }, "companions": { @@ -707,6 +708,16 @@ "conditional": "RASTER", "doc": "A raster tile. A MeosType no membership predicate admits, as Nsegment is." }, + "Raster": { + "kind": "leaf", + "parent": "Value", + "prefixes": [ + "raster" + ], + "temptype": null, + "conditional": "RASTER", + "doc": "A georeferenced raster of one or more bands, the value every raster accessor, clip, warp and polygonization takes. MEOS registers it in no enum, so it names no temptype." + }, "Pcschema": { "kind": "leaf", "parent": "Value", diff --git a/tests/test_object_model.py b/tests/test_object_model.py index 26905b3..db2d9ce 100644 --- a/tests/test_object_model.py +++ b/tests/test_object_model.py @@ -241,9 +241,23 @@ def test_a_type_meos_registers_in_no_enum_still_gets_a_class(self): unregistered = {n for n, s in nodes.items() if s["kind"] == "leaf" and s["temptype"] is None} self.assertEqual(unregistered, - {"Pcschema", "RTree", "RTreeNNCursor", "SPTree", + {"Pcschema", "Raster", "RTree", "RTreeNNCursor", "SPTree", "SPNNCursor", "MeosArray"}) + def test_a_raster_is_a_class_its_functions_are_methods_of(self): + # MEOS registers no MeosType for a raster, its tile Raquet being the type the + # temporal raster values carry, while every raster function takes one first. + om = attach_object_model({"functions": [ + {"name": n, "api": "public", + "params": [{"name": "rast", "cType": "const Raster *"}]} + for n in ("raster_copy", "raster_mem_size", "raster_width") + ]}, MODEL, None)["objectModel"] + self.assertEqual(om["classes"]["Raster"]["cType"], "Raster") + names = {m["function"]: m["ooName"] for m in om["classes"]["Raster"]["methods"]} + self.assertEqual(names, {"raster_copy": "copy", "raster_mem_size": "memSize", + "raster_width": "width"}) + self.assertEqual(om["summary"]["unclassified"], 0) + def test_a_function_named_as_its_own_prefix_still_has_a_member_name(self): # `meos_pc_schema` IS its class's prefix, so dropping the prefix leaves # nothing — the one case the override table exists for.