Skip to content

MetaDB: Map JSON configs to RDF#618

Merged
amrc-benmorrow merged 16 commits intomainfrom
bmz/metadb-structured
Apr 1, 2026
Merged

MetaDB: Map JSON configs to RDF#618
amrc-benmorrow merged 16 commits intomainfrom
bmz/metadb-structured

Conversation

@amrc-benmorrow
Copy link
Copy Markdown
Contributor

Start work on the mapping from structured RDF into the existing JSON config entries. Create a framework in which certain Apps are classified as Structured application, which means their JSON config entries are backed by RDF structure. Support pushing updates to the JSON back into the RDF, and regenerating the JSON when the RDF has changed.

For now only Object registration, General info and Sparkplug address are supported as Structured apps, and their mappings are hard-coded. Long-term these should be generated from some form of schema entry.

The regeneration code is rather simple-minded and regenerates all possible config entries on any change. This could be optimised in the future but the Jena ModelChangedListener facility is not as helpful as it could be so it will not be entirely straightforward, especially where config entries make use of the class structure. We must generate entries eagerly because we need to (eventually) support push notify.

@amrc-benmorrow amrc-benmorrow self-assigned this Mar 31, 2026
This is the Jena facility for watching changes to a graph. Support is
limited at the moment; specifically

- Transactions are not respected.
- While removals fire for inferred statements, additions do not.

Some of this can be worked around.
This will be particularly important when we are regenerating structured
config entries.
Currently this only updates _Object Registration_; it is also very crude
and always recalculates all possible entries. This is due to the
limitations of the ModelChangedListener interface. It may be possible to
optimise in the future.
In the current JS ConfigDB we store the rank of each object
individually. In this RDF version we are deriving it from member
relations, but this means the top rank class has no rank as well as no
class. Given that nothing should be depending on the numerical ranks
anyway I don't mind making this change.
All config changes which happen within a single transaction can and
should share the same starting Instant. However we don't want to
allocation an Instant to a txn unless it needs one. Refactor the
RequestHandler classes to accomodate this.

We need to special-case the Object Registration entry for the Instant:
if the Instant is not created until we start processing config updates,
it will not be caught by the initial pass.
Generate _General info_ entries as well. For the moment these are still
two hardcoded functions; it should be possible to generalise them.
Map the results of a Query into JSON, using the typing information from
the RDF to decide how to decode. This will only map to a single flat
JSON object at this point. The mapping between Application and Query is
still hardcoded for Registration and Info for now.

In order to generate the correct Registration output we need some
facilities for defaulting optional or nonexistent values. This can be
handled fairly cleanly in the SPARQL provided we can identify a
namespace of variable names which are not valid as JSON object keys.
We are going to need to maintain a permanent but changing list of
mappings for the structured apps. The AppUpdater object lives for a
single request so it is not a suitable place to hold this information.
I'm trying not to pull too much into the RDF rather than using the
existing dump files; there is a lot of information in there and I don't
really want to just rewrite it all in Turtle. But I want a structured
app other than Info, and I can't use Registration because that will need
to be special-cased on set in any case.
This is still limited to a few hardcoded Apps with handwritten SPARQL
queries. Updates to Registration will have to be handled specially.
This mostly consists of validation; only the class and deleted fields
can be changed for now.
Blank nodes behave strangely within SPARQL INSERTS: the spec says that
blank nodes in inserted triples must be new blank nodes distinct from
any other. Jena's mechanism for substitution into queries does not
override this, so if an existing blank is substituted into an INSERT the
inserted triples reference a new blank instead. This means we cannot
practically use blank nodes at all.

For now, create FP nodes under an ACS namespace. There are three
sensible options here: urn:uuid, an ACS namespace, and a namespace local
to the installation. Using urn:uuid causes issues with relative URL
resolution rules. Using a local namespace may be a better idea in the
long run, although ideally we would want to keep ACS objects under the
ACS prefix.
If we are not going to create config entries as blanks node, they need
IRIs; if they are going to have IRIs they need UUIDs generating and
might as well be F+ objects. Create a class Document ⊂ Individual and
make ConfigEntry a subclass.

* Use the ConfigEntry's own UUID for the etag.
* Remove the Instant handling for now. Ideally it would come back later
  applied to all Individuals but we don't need it for now.
* Config entries are now F+ objects so they have Registration entries.
  We must not generate these for Registration entries or we have an
  infinite loop. These could be supplied virtually as they are
  immutable.
* Delete orphaned structured config entries.
* Adjust some of the namespacing and use relative URLs within the Turtle
  rather than a plethora of namespaces.
@amrc-benmorrow amrc-benmorrow force-pushed the bmz/metadb-structured branch from c4f71ff to e56d40c Compare March 31, 2026 07:50
@KavanPrice
Copy link
Copy Markdown
Contributor

The move to this requestExecute model makes me think that we should have a look at Kafka again as a way of managing these requests to Jena.

@amrc-benmorrow amrc-benmorrow merged commit cb5f908 into main Apr 1, 2026
1 check passed
@amrc-benmorrow amrc-benmorrow deleted the bmz/metadb-structured branch April 1, 2026 08:47
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.

2 participants