Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | 3x 3x 3x 3x 3x 1x 1x 1x 3x 3x 4x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x | import * as vscode from 'vscode';
import { Store } from '@faubulous/mentor-rdf';
import { SparqlConnection } from './sparql-connection';
import { ComunicaEndpoint } from './sparql-endpoint';
import { TripleStoreConfig } from './triple-store-config';
import { ITripleStoreConfigService } from './triple-store-config-service.interface';
import { ISparqlConnectionRegistry } from './sparql-connection-registry.interface';
import { IDocumentConnectionService } from './document-connection-service.interface';
import { ISparqlQuerySourceFactory } from './sparql-query-source-factory.interface';
import { createFilteredSource } from './sparql-inference-filter';
/**
* Builds Comunica-compatible query sources. The workspace store yields an in-memory
* RDF/JS source; every other store type becomes an HTTP SPARQL endpoint whose URL
* receives the store config's URL-parameter reasoning control (if any).
*/
export class SparqlQuerySourceFactory implements ISparqlQuerySourceFactory {
/**
* Store-type ids already warned about this session, so the degradation
* warning fires once per store type rather than on every query.
*/
private readonly _warnedStoreTypes = new Set<string>();
constructor(
private readonly _store: Store,
private readonly _storeConfigService: ITripleStoreConfigService,
private readonly _connectionRegistry: ISparqlConnectionRegistry,
private readonly _documentConnectionService: IDocumentConnectionService
) { }
/**
* Gets a Comunica-compatible query source for a document or notebook cell. Uses the
* document-level inference setting if set, otherwise falls back to the connection setting.
* @param documentUri The URI of the document or notebook cell.
* @returns A promise that resolves to a Comunica source configuration.
*/
async getQuerySourceForDocument(documentUri: vscode.Uri): Promise<ComunicaEndpoint> {
const connection = this._documentConnectionService.getConnectionForDocument(documentUri);
const inferenceEnabled = this._documentConnectionService.getInferenceEnabledForDocument(documentUri);
return this._createQuerySource(connection, inferenceEnabled);
}
/**
* Gets a Comunica-compatible query source for a specific connection.
* @param connection The SPARQL connection.
* @param inferenceEnabled Optional inference override; defaults to the connection's persisted setting.
* @returns A promise that resolves to a Comunica source configuration.
*/
async getQuerySourceForConnection(connection: SparqlConnection, inferenceEnabled?: boolean): Promise<ComunicaEndpoint> {
const enabled = inferenceEnabled ?? this._connectionRegistry.getInferenceEnabled(connection.id);
return this._createQuerySource(connection, enabled);
}
/**
* Builds a Comunica-compatible source for a connection.
* @param connection The SPARQL connection.
* @param inferenceEnabled Whether inference should be enabled.
* @returns The resolved Comunica source configuration.
*/
private _createQuerySource(connection: SparqlConnection, inferenceEnabled: boolean): ComunicaEndpoint {
if (this._storeConfigService.isWorkspaceConnectionId(connection.id)) {
if (!inferenceEnabled) {
// Filter out inference graph quads.
return {
type: 'rdfjs',
value: createFilteredSource(this._store.asSource()),
};
} else E{
// Include all quads including inferred ones.
return {
type: 'rdfjs',
value: this._store.asSource(),
};
}
} else {
const store = this._storeConfigService.getStoreConfig(connection.storeType);
// A store type that no longer resolves (deleted, or defined in the user
// settings of another machine) silently degrades to generic SPARQL
// behavior: store-specific query templates and inference control are
// lost. Warn once per store type per session instead of hiding it.
Iif (connection.storeType !== undefined && store === undefined) {
this._warnUnresolvedStoreType(connection);
}
let value = connection.endpointUrl;
Eif (store?.inference?.supported && store.inference.urlParameters) {
try {
const url = new URL(connection.endpointUrl);
this._applyUrlInference(url, store, inferenceEnabled);
value = url.toString();
} catch {
// endpointUrl is not a valid absolute URL (e.g. mid-edit) — use it verbatim.
}
}
return { type: 'sparql', value, connection, inferenceEnabled };
}
}
/**
* Shows a one-time-per-session warning that a connection's store type is not
* defined on this machine, with an action to open the store settings.
* Fire-and-forget: query execution proceeds with the generic SPARQL fallback.
* @param connection The connection whose store type did not resolve.
*/
private _warnUnresolvedStoreType(connection: SparqlConnection): void {
const storeType = connection.storeType!;
if (this._warnedStoreTypes.has(storeType)) {
return;
}
this._warnedStoreTypes.add(storeType);
vscode.window.showWarningMessage(
`The store type "${storeType}" of the connection ${connection.endpointUrl} is not defined on this machine. `
+ 'Queries use generic SPARQL defaults; store-specific queries and inference control are unavailable.',
'Manage Stores'
).then(action => {
if (action === 'Manage Stores') {
vscode.commands.executeCommand('mentor.command.openSettings', 'query.stores');
}
});
}
/**
* Appends the store config's URL-parameter reasoning fragment to an endpoint URL, in place.
* No-op unless the store supports reasoning via `urlParameters` and the fragment is non-empty.
* @param url The endpoint URL to mutate.
* @param store The resolved store config.
* @param inferenceEnabled Whether inference is currently enabled.
*/
private _applyUrlInference(url: URL, store: TripleStoreConfig | undefined, inferenceEnabled: boolean): void {
const inference = store?.inference;
Iif (!inference?.supported || !inference.urlParameters) {
return;
}
const fragment = (inferenceEnabled ? inference.urlParameters.enabled : inference.urlParameters.disabled)?.trim().replace(/^[?&]+/, '');
Iif (!fragment) {
return;
}
// Append verbatim, preserving the user's exact fragment (no re-encoding/reordering).
const existing = url.search.replace(/^\?/, '');
url.search = existing ? `${existing}&${fragment}` : fragment;
}
}
|