var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { normalizeQueryText } from "../textHash";
import { WorkspaceBackendError } from "./errors";
function stripTrailingSlash(value) {
    return value.replace(/\/+$/, "");
}
function splitPath(path) {
    return path.split("/").filter(Boolean);
}
function nowIso() {
    return new Date().toISOString();
}
function sparqlStringLiteral(value) {
    const escaped = value
        .replace(/\\/g, "\\\\")
        .replace(/\r/g, "\\r")
        .replace(/\n/g, "\\n")
        .replace(/\t/g, "\\t")
        .replace(/\"/g, '\\"');
    return `"${escaped}"`;
}
function iri(iriValue) {
    const trimmed = iriValue.trim();
    if (!trimmed)
        throw new Error("IRI is required");
    return `<${trimmed.replace(/>/g, "%3E")}>`;
}
function uuidV4() {
    const cryptoObj = globalThis.crypto;
    if (cryptoObj === null || cryptoObj === void 0 ? void 0 : cryptoObj.randomUUID)
        return cryptoObj.randomUUID();
    const rnds = new Uint8Array(16);
    if (cryptoObj === null || cryptoObj === void 0 ? void 0 : cryptoObj.getRandomValues) {
        cryptoObj.getRandomValues(rnds);
    }
    else {
        for (let i = 0; i < rnds.length; i++)
            rnds[i] = Math.floor(Math.random() * 256);
    }
    rnds[6] = (rnds[6] & 0x0f) | 0x40;
    rnds[8] = (rnds[8] & 0x3f) | 0x80;
    const hex = Array.from(rnds, (b) => b.toString(16).padStart(2, "0")).join("");
    return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
}
function mintManagedQueryVersionIri(workspaceIri) {
    return `${workspaceIri.trim()}_mq_v_${uuidV4()}`;
}
function isIriLike(value) {
    return /^[a-z][a-z0-9+.-]*:/i.test(value.trim());
}
function mintFolderIri(workspaceIri, folderPath) {
    const base = stripTrailingSlash(workspaceIri);
    return `${base}/folder/${encodeURIComponent(folderPath)}`;
}
function tryParseFolderPathFromFolderIri(workspaceIri, folderIri) {
    const base = stripTrailingSlash(workspaceIri);
    const prefix = `${base}/folder/`;
    if (!folderIri.startsWith(prefix))
        return undefined;
    const encoded = folderIri.slice(prefix.length);
    try {
        return decodeURIComponent(encoded);
    }
    catch (_a) {
        return undefined;
    }
}
function mapHttpError(status, message) {
    if (status === 401)
        return new WorkspaceBackendError("AUTH_FAILED", message || "Authentication failed");
    if (status === 403)
        return new WorkspaceBackendError("FORBIDDEN", message || "Forbidden");
    if (status === 404)
        return new WorkspaceBackendError("NOT_FOUND", message || "Not found");
    if (status === 409)
        return new WorkspaceBackendError("CONFLICT", message || "Conflict");
    if (status === 429)
        return new WorkspaceBackendError("RATE_LIMITED", message || "Rate limited");
    if (status >= 500)
        return new WorkspaceBackendError("NETWORK_ERROR", message || "Server error");
    return new WorkspaceBackendError("UNKNOWN", message || `HTTP ${status}`);
}
export default class SparqlWorkspaceBackend {
    constructor(config, options) {
        this.config = config;
        this.options = options;
        this.type = "sparql";
    }
    resolveAuthHeaders() {
        return __awaiter(this, void 0, void 0, function* () {
            var _a, _b, _c;
            try {
                const dynamic = yield ((_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.getAuthHeaders) === null || _b === void 0 ? void 0 : _b.call(_a));
                if (dynamic)
                    return dynamic;
            }
            catch (e) {
                console.error("Failed to resolve SPARQL auth headers", e);
            }
            return ((_c = this.options) === null || _c === void 0 ? void 0 : _c.authHeaders) || {};
        });
    }
    sparqlQuery(query) {
        return __awaiter(this, void 0, void 0, function* () {
            const body = new URLSearchParams();
            body.set("query", query);
            if (this.config.defaultGraph)
                body.set("default-graph-uri", this.config.defaultGraph);
            const authHeaders = yield this.resolveAuthHeaders();
            let res;
            try {
                res = yield fetch(this.config.endpoint, {
                    method: "POST",
                    headers: Object.assign({ Accept: "application/sparql-results+json", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" }, authHeaders),
                    body: body.toString(),
                });
            }
            catch (e) {
                throw new WorkspaceBackendError("NETWORK_ERROR", e instanceof Error ? e.message : String(e));
            }
            if (!res.ok) {
                const text = yield res.text().catch(() => "");
                throw mapHttpError(res.status, text || `SPARQL endpoint responded with ${res.status}`);
            }
            try {
                return (yield res.json());
            }
            catch (e) {
                throw new WorkspaceBackendError("UNKNOWN", e instanceof Error ? e.message : "Invalid SPARQL JSON response");
            }
        });
    }
    sparqlUpdate(update) {
        return __awaiter(this, void 0, void 0, function* () {
            const body = new URLSearchParams();
            body.set("update", update);
            if (this.config.defaultGraph)
                body.set("default-graph-uri", this.config.defaultGraph);
            const authHeaders = yield this.resolveAuthHeaders();
            let res;
            try {
                res = yield fetch(this.config.endpoint, {
                    method: "POST",
                    headers: Object.assign({ Accept: "application/sparql-results+json, */*", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" }, authHeaders),
                    body: body.toString(),
                });
            }
            catch (e) {
                throw new WorkspaceBackendError("NETWORK_ERROR", e instanceof Error ? e.message : String(e));
            }
            if (!res.ok) {
                const text = yield res.text().catch(() => "");
                throw mapHttpError(res.status, text || `SPARQL endpoint responded with ${res.status}`);
            }
        });
    }
    getBindings(results) {
        var _a;
        return ((_a = results === null || results === void 0 ? void 0 : results.results) === null || _a === void 0 ? void 0 : _a.bindings) || [];
    }
    folderIriFromId(folderId) {
        if (!folderId)
            return this.config.workspaceIri;
        return mintFolderIri(this.config.workspaceIri, folderId);
    }
    resolveManagedQueryIri(queryIdOrIri) {
        const trimmed = queryIdOrIri.trim();
        if (!trimmed)
            throw new WorkspaceBackendError("UNKNOWN", "Query ID is required");
        if (isIriLike(trimmed))
            return trimmed;
        throw new WorkspaceBackendError("UNKNOWN", "SPARQL managed query IDs must be IRIs");
    }
    validateAccess() {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.sparqlQuery(`SELECT (1 AS ?ok) WHERE {} LIMIT 1`);
        });
    }
    listFolder(folderId) {
        return __awaiter(this, void 0, void 0, function* () {
            var _a, _b, _c, _d, _e;
            const workspaceIri = this.config.workspaceIri;
            const containerIri = this.folderIriFromId(folderId);
            const folderFilter = folderId ? `?folder skos:broader ${iri(containerIri)} .` : `FILTER(!BOUND(?parent))`;
            const foldersQuery = `
PREFIX yasgui:  <https://matdata.eu/ns/yasgui#>
PREFIX skos:    <http://www.w3.org/2004/02/skos/core#>
PREFIX rdfs:    <http://www.w3.org/2000/01/rdf-schema#>

SELECT ?folder ?label ?parent WHERE {
  ?folder a yasgui:WorkspaceFolder ;
          skos:inScheme ${iri(workspaceIri)} ;
          rdfs:label ?label .
  OPTIONAL { ?folder skos:broader ?parent }
  ${folderFilter}
}
ORDER BY LCASE(STR(?label))`;
            const queriesQuery = `
PREFIX yasgui:  <https://matdata.eu/ns/yasgui#>
PREFIX dcterms: <http://purl.org/dc/terms/>
PREFIX rdfs:    <http://www.w3.org/2000/01/rdf-schema#>

SELECT ?mq ?label WHERE {
  ?mq a yasgui:ManagedQuery ;
      rdfs:label ?label ;
      dcterms:isPartOf ${iri(containerIri)} .
}
ORDER BY LCASE(STR(?label))`;
            const [foldersRes, queriesRes] = yield Promise.all([
                this.sparqlQuery(foldersQuery),
                this.sparqlQuery(queriesQuery),
            ]);
            const folders = [];
            for (const row of this.getBindings(foldersRes)) {
                const folder = (_a = row.folder) === null || _a === void 0 ? void 0 : _a.value;
                const label = (_b = row.label) === null || _b === void 0 ? void 0 : _b.value;
                if (!folder || !label)
                    continue;
                const folderPath = tryParseFolderPathFromFolderIri(workspaceIri, folder) || label;
                const parentIri = (_c = row.parent) === null || _c === void 0 ? void 0 : _c.value;
                const parentPath = parentIri ? tryParseFolderPathFromFolderIri(workspaceIri, parentIri) : undefined;
                folders.push({
                    kind: "folder",
                    id: folderPath,
                    label,
                    parentId: parentPath,
                });
            }
            const queries = [];
            for (const row of this.getBindings(queriesRes)) {
                const mqIri = (_d = row.mq) === null || _d === void 0 ? void 0 : _d.value;
                const label = (_e = row.label) === null || _e === void 0 ? void 0 : _e.value;
                if (!mqIri || !label)
                    continue;
                queries.push({
                    kind: "query",
                    id: mqIri,
                    label,
                    parentId: folderId || undefined,
                });
            }
            const out = [...folders, ...queries];
            out.sort((a, b) => a.label.localeCompare(b.label));
            return out;
        });
    }
    searchByName(query) {
        return __awaiter(this, void 0, void 0, function* () {
            var _a, _b, _c;
            const q = query.trim();
            if (!q)
                return [];
            const workspaceIri = this.config.workspaceIri;
            const queryText = `
PREFIX yasgui:  <https://matdata.eu/ns/yasgui#>
PREFIX dcterms: <http://purl.org/dc/terms/>
PREFIX skos:    <http://www.w3.org/2004/02/skos/core#>
PREFIX rdfs:    <http://www.w3.org/2000/01/rdf-schema#>

SELECT ?mq ?label ?container WHERE {
  ?mq a yasgui:ManagedQuery ;
      rdfs:label ?label ;
      dcterms:isPartOf ?container .

  {
    FILTER(?container = ${iri(workspaceIri)})
  } UNION {
    ?container a yasgui:WorkspaceFolder ; skos:inScheme ${iri(workspaceIri)} .
  }

  FILTER(CONTAINS(LCASE(STR(?label)), LCASE(${sparqlStringLiteral(q)})))
}
ORDER BY LCASE(STR(?label))`;
            const res = yield this.sparqlQuery(queryText);
            const hits = [];
            for (const row of this.getBindings(res)) {
                const mqIri = (_a = row.mq) === null || _a === void 0 ? void 0 : _a.value;
                const label = (_b = row.label) === null || _b === void 0 ? void 0 : _b.value;
                const container = (_c = row.container) === null || _c === void 0 ? void 0 : _c.value;
                if (!mqIri || !label || !container)
                    continue;
                const parentId = container === workspaceIri ? undefined : tryParseFolderPathFromFolderIri(workspaceIri, container) || undefined;
                hits.push({ kind: "query", id: mqIri, label, parentId });
            }
            hits.sort((a, b) => a.label.localeCompare(b.label));
            return hits;
        });
    }
    readQuery(queryId) {
        return __awaiter(this, void 0, void 0, function* () {
            var _a, _b, _c, _d;
            const mqIri = this.resolveManagedQueryIri(queryId);
            const query = `
PREFIX yasgui:  <https://matdata.eu/ns/yasgui#>
PREFIX dcterms: <http://purl.org/dc/terms/>
PREFIX prov:    <http://www.w3.org/ns/prov#>
PREFIX spin:    <http://spinrdf.org/spin#>
PREFIX sd:      <http://www.w3.org/ns/sparql-service-description#>

SELECT ?version ?created ?text ?endpoint ?description WHERE {
  ?version a yasgui:ManagedQueryVersion ;
           dcterms:isVersionOf ${iri(mqIri)} ;
           dcterms:created ?created ;
           spin:text ?text .

  OPTIONAL { ?version dcterms:description ?description }

  OPTIONAL {
    ?version prov:used ?svc .
    ?svc a sd:Service ;
         sd:endpoint ?endpoint .
  }

}
ORDER BY DESC(?created)
LIMIT 1`;
            const res = yield this.sparqlQuery(query);
            const row = this.getBindings(res)[0];
            if (!row)
                throw new WorkspaceBackendError("NOT_FOUND", "Query not found");
            const text = (_a = row.text) === null || _a === void 0 ? void 0 : _a.value;
            const version = (_b = row.version) === null || _b === void 0 ? void 0 : _b.value;
            const endpoint = (_c = row.endpoint) === null || _c === void 0 ? void 0 : _c.value;
            const description = (_d = row.description) === null || _d === void 0 ? void 0 : _d.value;
            if (!text || !version)
                throw new WorkspaceBackendError("NOT_FOUND", "Query not found");
            return {
                queryText: text,
                versionTag: version,
                associatedEndpoint: endpoint,
                description,
            };
        });
    }
    renameQuery(queryId, newLabel) {
        return __awaiter(this, void 0, void 0, function* () {
            var _a;
            const label = newLabel.trim();
            if (!label)
                throw new WorkspaceBackendError("UNKNOWN", "New name is required");
            const mqIriValue = this.resolveManagedQueryIri(queryId);
            const containerIriValue = yield (() => __awaiter(this, void 0, void 0, function* () {
                var _a;
                const q = `
PREFIX yasgui:  <https://matdata.eu/ns/yasgui#>
PREFIX dcterms: <http://purl.org/dc/terms/>

SELECT ?container WHERE {
  ${iri(mqIriValue)} a yasgui:ManagedQuery ;
    dcterms:isPartOf ?container .
}
LIMIT 1`;
                const res = yield this.sparqlQuery(q);
                const row = this.getBindings(res)[0];
                const container = (_a = row === null || row === void 0 ? void 0 : row.container) === null || _a === void 0 ? void 0 : _a.value;
                if (!container)
                    throw new WorkspaceBackendError("NOT_FOUND", "Query not found");
                return container;
            }))();
            {
                const dupCheck = `
PREFIX yasgui:  <https://matdata.eu/ns/yasgui#>
PREFIX dcterms: <http://purl.org/dc/terms/>
PREFIX rdfs:    <http://www.w3.org/2000/01/rdf-schema#>

SELECT ?mq WHERE {
  ?mq a yasgui:ManagedQuery ;
      dcterms:isPartOf ${iri(containerIriValue)} ;
      rdfs:label ?lbl .
  FILTER(LCASE(STR(?lbl)) = LCASE(${sparqlStringLiteral(label)}))
  FILTER(?mq != ${iri(mqIriValue)})
}
LIMIT 1`;
                const res = yield this.sparqlQuery(dupCheck);
                const row = this.getBindings(res)[0];
                if ((_a = row === null || row === void 0 ? void 0 : row.mq) === null || _a === void 0 ? void 0 : _a.value) {
                    throw new WorkspaceBackendError("CONFLICT", `A query named '${label}' already exists in this folder. Please choose a different name.`);
                }
            }
            const mqIri = mqIriValue;
            const update = `
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

DELETE { ${iri(mqIri)} rdfs:label ?oldLabel . }
INSERT { ${iri(mqIri)} rdfs:label ${sparqlStringLiteral(label)} . }
WHERE  { OPTIONAL { ${iri(mqIri)} rdfs:label ?oldLabel . } }
`;
            yield this.sparqlUpdate(update);
        });
    }
    deleteQuery(queryId) {
        return __awaiter(this, void 0, void 0, function* () {
            const mqIri = this.resolveManagedQueryIri(queryId);
            const update = `
PREFIX dcterms: <http://purl.org/dc/terms/>

DELETE {
  ${iri(mqIri)} ?p ?o .
  ?s ?pp ${iri(mqIri)} .
  ?v ?vp ?vo .
  ?sv ?svP ?v .
}
WHERE {
  OPTIONAL { ${iri(mqIri)} ?p ?o . }
  OPTIONAL { ?s ?pp ${iri(mqIri)} . }
  OPTIONAL {
    ?v dcterms:isVersionOf ${iri(mqIri)} .
    OPTIONAL { ?v ?vp ?vo . }
    OPTIONAL { ?sv ?svP ?v . }
  }
}
`;
            yield this.sparqlUpdate(update);
        });
    }
    renameFolder(folderId, newLabel) {
        return __awaiter(this, void 0, void 0, function* () {
            const label = newLabel.trim();
            if (!label)
                throw new WorkspaceBackendError("UNKNOWN", "New name is required");
            const folderIriValue = mintFolderIri(this.config.workspaceIri, folderId);
            const update = `
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

DELETE { ${iri(folderIriValue)} rdfs:label ?oldLabel . }
INSERT { ${iri(folderIriValue)} rdfs:label ${sparqlStringLiteral(label)} . }
WHERE  { OPTIONAL { ${iri(folderIriValue)} rdfs:label ?oldLabel . } }
`;
            yield this.sparqlUpdate(update);
        });
    }
    deleteFolder(folderId) {
        return __awaiter(this, void 0, void 0, function* () {
            const workspaceIri = this.config.workspaceIri;
            const rootFolderIri = mintFolderIri(workspaceIri, folderId);
            const update = `
PREFIX yasgui:  <https://matdata.eu/ns/yasgui#>
PREFIX dcterms: <http://purl.org/dc/terms/>
PREFIX skos:    <http://www.w3.org/2004/02/skos/core#>

DELETE {
  ?folder ?fp ?fo .
  ?sf ?sfp ?folder .

  ?mq ?mp ?mo .
  ?sm ?smp ?mq .

  ?v ?vp ?vo .
  ?sv ?svP ?v .
}
WHERE {
  {
    SELECT DISTINCT ?folder WHERE {
      ?folder a yasgui:WorkspaceFolder ;
              skos:inScheme ${iri(workspaceIri)} .
      ?folder (skos:broader)* ${iri(rootFolderIri)} .
    }
  }

  OPTIONAL { ?folder ?fp ?fo . }
  OPTIONAL { ?sf ?sfp ?folder . }

  OPTIONAL {
    ?mq a yasgui:ManagedQuery ;
        dcterms:isPartOf ?folder .
    OPTIONAL { ?mq ?mp ?mo . }
    OPTIONAL { ?sm ?smp ?mq . }

    OPTIONAL {
      ?v dcterms:isVersionOf ?mq .
      OPTIONAL { ?v ?vp ?vo . }
      OPTIONAL { ?sv ?svP ?v . }
    }
  }
}
`;
            yield this.sparqlUpdate(update);
        });
    }
    writeQuery(queryId, queryText, options) {
        return __awaiter(this, void 0, void 0, function* () {
            var _a, _b, _c, _d, _e;
            const workspaceIri = this.config.workspaceIri;
            const mqIriValue = this.resolveManagedQueryIri(queryId);
            let folderPath = ((options === null || options === void 0 ? void 0 : options.folderId) || "").trim();
            let label = ((options === null || options === void 0 ? void 0 : options.label) || "").trim();
            if (!label) {
                const q = `
PREFIX yasgui:  <https://matdata.eu/ns/yasgui#>
PREFIX dcterms: <http://purl.org/dc/terms/>
PREFIX rdfs:    <http://www.w3.org/2000/01/rdf-schema#>

SELECT ?label ?container WHERE {
  ${iri(mqIriValue)} a yasgui:ManagedQuery ;
    rdfs:label ?label ;
    dcterms:isPartOf ?container .
}
LIMIT 1`;
                const res = yield this.sparqlQuery(q);
                const row = this.getBindings(res)[0];
                const fetchedLabel = (_a = row === null || row === void 0 ? void 0 : row.label) === null || _a === void 0 ? void 0 : _a.value;
                const container = (_b = row === null || row === void 0 ? void 0 : row.container) === null || _b === void 0 ? void 0 : _b.value;
                if (!fetchedLabel || !container)
                    throw new WorkspaceBackendError("NOT_FOUND", "Query not found");
                label = fetchedLabel;
                if (!folderPath && container !== workspaceIri) {
                    folderPath = tryParseFolderPathFromFolderIri(workspaceIri, container) || "";
                }
            }
            if (!label.trim())
                throw new WorkspaceBackendError("UNKNOWN", "Query name is required");
            const containerIriValue = folderPath ? mintFolderIri(workspaceIri, folderPath) : workspaceIri;
            {
                const dupCheck = `
PREFIX yasgui:  <https://matdata.eu/ns/yasgui#>
PREFIX dcterms: <http://purl.org/dc/terms/>
PREFIX rdfs:    <http://www.w3.org/2000/01/rdf-schema#>

SELECT ?mq WHERE {
  ?mq a yasgui:ManagedQuery ;
      dcterms:isPartOf ${iri(containerIriValue)} ;
      rdfs:label ?lbl .
  FILTER(LCASE(STR(?lbl)) = LCASE(${sparqlStringLiteral(label)}))
  FILTER(?mq != ${iri(mqIriValue)})
}
LIMIT 1`;
                const res = yield this.sparqlQuery(dupCheck);
                const row = this.getBindings(res)[0];
                if ((_c = row === null || row === void 0 ? void 0 : row.mq) === null || _c === void 0 ? void 0 : _c.value) {
                    throw new WorkspaceBackendError("CONFLICT", `A query named '${label}' already exists in this folder. Please choose a different name.`);
                }
            }
            if (options === null || options === void 0 ? void 0 : options.expectedVersionTag) {
                try {
                    const current = yield this.readQuery(queryId);
                    if (current.versionTag && current.versionTag !== options.expectedVersionTag) {
                        throw new WorkspaceBackendError("CONFLICT", "Version tag mismatch");
                    }
                }
                catch (e) {
                    const err = e;
                    if ((err === null || err === void 0 ? void 0 : err.code) && err.code !== "NOT_FOUND")
                        throw e;
                }
            }
            try {
                const current = yield this.readQuery(queryId);
                if (normalizeQueryText(current.queryText) === normalizeQueryText(queryText)) {
                    return;
                }
            }
            catch (e) {
                const err = e;
                if ((err === null || err === void 0 ? void 0 : err.code) && err.code !== "NOT_FOUND")
                    throw e;
            }
            const versionIriValue = mintManagedQueryVersionIri(workspaceIri);
            const createdAt = nowIso();
            const description = (_d = options === null || options === void 0 ? void 0 : options.message) === null || _d === void 0 ? void 0 : _d.trim();
            const associatedEndpoint = (_e = options === null || options === void 0 ? void 0 : options.associatedEndpoint) === null || _e === void 0 ? void 0 : _e.trim();
            const folderTriples = [];
            if (folderPath) {
                const parts = splitPath(folderPath);
                for (let i = 0; i < parts.length; i++) {
                    const subPath = parts.slice(0, i + 1).join("/");
                    const folderIriValue = mintFolderIri(workspaceIri, subPath);
                    const folderLabel = parts[i];
                    folderTriples.push(`${iri(folderIriValue)} a <https://matdata.eu/ns/yasgui#WorkspaceFolder> ;`);
                    folderTriples.push(`  <http://www.w3.org/2004/02/skos/core#inScheme> ${iri(workspaceIri)} ;`);
                    folderTriples.push(`  <http://www.w3.org/2000/01/rdf-schema#label> ${sparqlStringLiteral(folderLabel)} .`);
                    if (i > 0) {
                        const parentPath = parts.slice(0, i).join("/");
                        const parentIri = mintFolderIri(workspaceIri, parentPath);
                        folderTriples.push(`${iri(folderIriValue)} <http://www.w3.org/2004/02/skos/core#broader> ${iri(parentIri)} .`);
                    }
                }
            }
            const update = `
PREFIX yasgui:  <https://matdata.eu/ns/yasgui#>
PREFIX dcterms: <http://purl.org/dc/terms/>
PREFIX prov:    <http://www.w3.org/ns/prov#>
  PREFIX sd:      <http://www.w3.org/ns/sparql-service-description#>
PREFIX skos:    <http://www.w3.org/2004/02/skos/core#>
PREFIX spin:    <http://spinrdf.org/spin#>
PREFIX rdfs:    <http://www.w3.org/2000/01/rdf-schema#>

INSERT DATA {
  ${iri(workspaceIri)} a yasgui:Workspace .

  ${folderTriples.join("\n  ")}

  ${iri(mqIriValue)} a yasgui:ManagedQuery ;
    rdfs:label ${sparqlStringLiteral(label)} ;
    dcterms:isPartOf ${iri(containerIriValue)} .

  ${iri(versionIriValue)} a yasgui:ManagedQueryVersion ;
    dcterms:isVersionOf ${iri(mqIriValue)} ;
    dcterms:created ${sparqlStringLiteral(createdAt)}^^<http://www.w3.org/2001/XMLSchema#dateTime> ;
    spin:text ${sparqlStringLiteral(queryText)}${description ? `;\n    dcterms:description ${sparqlStringLiteral(description)}` : ""}${associatedEndpoint ? `;\n    prov:used _:svc` : ""} .

  ${associatedEndpoint ? `_:svc a sd:Service ;\n    sd:endpoint ${iri(associatedEndpoint)} .` : ""}
}`;
            yield this.sparqlUpdate(update);
        });
    }
    listVersions(queryId) {
        return __awaiter(this, void 0, void 0, function* () {
            var _a, _b, _c, _d;
            const mqIri = this.resolveManagedQueryIri(queryId);
            const query = `
PREFIX yasgui:  <https://matdata.eu/ns/yasgui#>
PREFIX dcterms: <http://purl.org/dc/terms/>

SELECT ?version ?created ?creator ?message WHERE {
  ?version a yasgui:ManagedQueryVersion ;
           dcterms:isVersionOf ${iri(mqIri)} ;
           dcterms:created ?created .
  OPTIONAL { ?version dcterms:creator ?creator }
  OPTIONAL { ?version dcterms:description ?message }
}
ORDER BY DESC(?created)`;
            const res = yield this.sparqlQuery(query);
            const versions = [];
            for (const row of this.getBindings(res)) {
                const version = (_a = row.version) === null || _a === void 0 ? void 0 : _a.value;
                const createdAt = (_b = row.created) === null || _b === void 0 ? void 0 : _b.value;
                if (!version || !createdAt)
                    continue;
                versions.push({
                    id: version,
                    createdAt,
                    author: (_c = row.creator) === null || _c === void 0 ? void 0 : _c.value,
                    message: (_d = row.message) === null || _d === void 0 ? void 0 : _d.value,
                });
            }
            return versions;
        });
    }
    readVersion(queryId, versionId) {
        return __awaiter(this, void 0, void 0, function* () {
            var _a, _b, _c;
            const mqIri = this.resolveManagedQueryIri(queryId);
            const query = `
PREFIX yasgui:  <https://matdata.eu/ns/yasgui#>
PREFIX dcterms: <http://purl.org/dc/terms/>
PREFIX prov:    <http://www.w3.org/ns/prov#>
PREFIX spin:    <http://spinrdf.org/spin#>
PREFIX sd:      <http://www.w3.org/ns/sparql-service-description#>

SELECT ?text ?endpoint ?description WHERE {
  ${iri(versionId)} a yasgui:ManagedQueryVersion ;
    dcterms:isVersionOf ${iri(mqIri)} ;
    spin:text ?text .

  OPTIONAL { ${iri(versionId)} dcterms:description ?description }
  OPTIONAL {
    ${iri(versionId)} prov:used ?svc .
    ?svc a sd:Service ;
         sd:endpoint ?endpoint .
  }
}
LIMIT 1`;
            const res = yield this.sparqlQuery(query);
            const row = this.getBindings(res)[0];
            if (!row)
                throw new WorkspaceBackendError("NOT_FOUND", "Version not found");
            const text = (_a = row.text) === null || _a === void 0 ? void 0 : _a.value;
            if (!text)
                throw new WorkspaceBackendError("NOT_FOUND", "Version not found");
            return {
                queryText: text,
                versionTag: versionId,
                associatedEndpoint: (_b = row.endpoint) === null || _b === void 0 ? void 0 : _b.value,
                description: (_c = row.description) === null || _c === void 0 ? void 0 : _c.value,
            };
        });
    }
}
//# sourceMappingURL=SparqlWorkspaceBackend.js.map