|
1 | 1 | from abc import ABC, abstractmethod |
| 2 | +import json |
2 | 3 | import logging |
3 | 4 | from typing import Type, Dict, Optional, Any, List, ClassVar, Union |
4 | 5 | from pydantic import BaseModel, Field, ConfigDict |
|
9 | 10 | from rdflib.query import Result |
10 | 11 |
|
11 | 12 |
|
| 13 | +# JSON-LD keyword set used to recognise a top-level dict as RDF data rather |
| 14 | +# than generic JSON to recurse into. Presence of any of these at the root is |
| 15 | +# a strong, unambiguous signal — they are JSON-LD reserved terms with no |
| 16 | +# legitimate meaning in non-RDF JSON. |
| 17 | +_JSONLD_KEYS = ("@context", "@graph", "@id", "@type") |
| 18 | + |
| 19 | + |
12 | 20 | class Operation(ABC, BaseModel): |
13 | 21 | """ |
14 | 22 | Abstract base class for all operations with dual execution paths: |
@@ -91,7 +99,24 @@ def process_json( |
91 | 99 | # Return RDFLib objects as-is for operation chaining |
92 | 100 | return result |
93 | 101 |
|
94 | | - # 🔁 Recurse into each value — allows nested @op inside JSON-LD and SPARQL bindings |
| 102 | + # JSON-LD shape recognition — a dict carrying any JSON-LD reserved |
| 103 | + # key is RDF data, not generic JSON to recurse into. Parse it |
| 104 | + # once at the runtime layer so every consuming op (POST, PUT, |
| 105 | + # Merge, ldh-Create*/Add*) receives an `rdflib.Graph` directly |
| 106 | + # instead of re-parsing identically inside its own |
| 107 | + # `execute_json`. Symmetric with the bare-value auto-wrap |
| 108 | + # below: that branch turns a JSON scalar into the matching |
| 109 | + # RDFLib term; this branch turns a JSON-LD object into the |
| 110 | + # matching RDFLib graph. |
| 111 | + if any(k in json_data for k in _JSONLD_KEYS): |
| 112 | + graph = Graph() |
| 113 | + graph.parse(data=json.dumps(json_data), format="json-ld") |
| 114 | + return graph |
| 115 | + |
| 116 | + # 🔁 Recurse into each value — allows nested @op inside generic |
| 117 | + # JSON structures (e.g. SPARQL binding objects), without |
| 118 | + # collapsing pure-data dicts that JSON-LD detection above |
| 119 | + # already handled. |
95 | 120 | return { |
96 | 121 | k: cls.process_json(settings, v, context, variable_stack) |
97 | 122 | for k, v in json_data.items() |
|
0 commit comments