More on the topic…
SPARQL queries have a fundamental problem: they're treated like raw SQL calls with no real infrastructure around them. The author identifies seven concrete issues. There's no access control—anyone with graph access sees everything. Simple queries can crash systems with billion-triple datasets. Prompt injection is a real threat. Most people lack the schema knowledge to write queries safely. Parameterization is clunky, typically done through VALUES keywords or external dictionaries. SPARQL UPDATE operations are particularly dangerous because even trivial updates can cause serious damage. And critically, when you export a dataset, you lose the query logic that gives the data meaning—the two get separated.
The solution is named queries: storing SPARQL queries as RDF triples within the graph itself, wrapped with metadata. This isn't novel—APIs have encapsulated queries for years—but keeping them as text in the database creates real advantages. Metadata can include SHACL schemas describing parameters and expected outputs, letting AI agents decide which query to run. You add new queries by inserting triples, not recompiling code. All reads and writes go through these named interfaces, never directly to the graph, which means you can enforce access control and log every interaction. You can inject user identity information that changes results based on permissions—something much harder with inline queries. The author has tested these ideas in practice.
The concrete implementation uses a self-describing structure in Turtle format. A named query object stores the SPARQL text, query type, description, and parameter definitions. Parameters use text placeholders like `{{class}}` that get substituted before parsing, not SPARQL variables—this matters because placeholders can sit anywhere, even inside FILTER clauses. Required parameters are enforced; optional ones fall back to defaults. The example query retrieves instances of a class with optional substring filtering on labels and comments. Using `COALESCE(STR(?label), "")` handles unbound variables gracefully, treating missing data the same as empty data so filters work predictably. This structure lets the system understand what each query does, what it needs, and what it returns.
Questions about this article
No questions yet.