///|
fn select_dataset(
data : Dataset,
sources : Array[(Term, Bool)],
budget : Budget,
) -> Dataset raise QueryError {
if sources.is_empty() {
return data
}
let quads = []
let names = []
let selected : Map[(String, Bool), Bool] = Map([])
let scope : BlankScope = { used: Map([]), mapping: Map([]), next: 0, budget, }
// Fresh default-graph blanks must not collide with the retained named graphs.
for q in data.facts {
scope.remember(q.subject)
scope.remember(q.object)
}
for (source, named) in sources {
budget.tick()
let key = source.key()
if selected.contains((key, named)) {
continue
}
selected[(key, named)] = true
let ids = match data.graphs.get(key) {
Some(ids) => ids
None => raise InvalidInput("no local RDF source for " + source.lexical)
}
if named {
names.push(source)
}
scope.mapping.clear()
for id in ids {
budget.tick()
let q = data.facts[id]
if quads.length() >= budget.limits.max_triples {
raise Resource("selected dataset quads")
}
quads.push(
if named {
q
} else {
{
..q,
graph: None,
subject: scope.rename(q.subject),
object: scope.rename(q.object),
}
},
)
}
}
Dataset::from_quads(quads, named_graphs=names, limits=budget.limits)
}
///|
/// Assemble a default Turtle document and explicitly named local documents.
/// Blank-node labels are scoped to each document, including empty named graphs.
pub fn Dataset::from_documents(
default_graph : String,
named_graphs : Array[(Term, String)],
limits~ : Limits = Limits::default(),
) -> Dataset raise QueryError {
let budget = Budget::new(limits)
if named_graphs.length() > limits.max_triples ||
default_graph.length() > limits.max_query_chars {
raise Resource("dataset documents")
}
let mut units = default_graph.length()
let declared : Map[String, Bool] = Map([])
let names = []
for (name, source) in named_graphs {
budget.tick()
if name.kind != IriKind || declared.contains(name.key()) {
raise InvalidInput("duplicate or invalid named document IRI")
}
if source.length() > limits.max_query_chars - units {
raise Resource("dataset document characters")
}
units += source.length()
declared[name.key()] = true
names.push(name)
}
let facts = Dataset::from_turtle(default_graph, limits~).facts.copy()
let scope : BlankScope = { used: Map([]), mapping: Map([]), next: 0, budget, }
for q in facts {
scope.remember(q.subject)
scope.remember(q.object)
}
for (name, source) in named_graphs {
let document = Dataset::from_turtle(source, limits~)
if document.length() > limits.max_triples - facts.length() {
raise Resource("dataset document quads")
}
scope.mapping.clear()
for q in document.facts {
facts.push({
..q,
graph: Some(name),
subject: scope.rename(q.subject),
object: scope.rename(q.object),
})
}
}
Dataset::from_quads(facts, named_graphs=names, limits~)
}