UNPKG

sparnatural

Version:

Visual client-side SPARQL query builder and knowledge graph exploration tool

330 lines 21.1 kB
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _WidgetFactory_instances, _WidgetFactory_getFinalQueryString; import { Config } from "../../../../../ontologies/SparnaturalConfig"; import { Datasources } from "../../../../../ontologies/SparnaturalConfigDatasources"; import { AutoCompleteWidget } from "../../../../widgets/AutoCompleteWidget"; import { BooleanWidget } from "../../../../widgets/BooleanWidget"; import { ListSparqlTemplateQueryBuilder, AutocompleteSparqlTemplateQueryBuilder, TreeSparqlTemplateQueryBuilder, ValuesListSparqlTemplateQueryBuilder } from "../../../../datasources/SparqlBuilders"; import { ListWidget } from "../../../../widgets/ListWidget"; import MapWidget from "../../../../widgets/MapWidget"; import { NoWidget } from "../../../../widgets/NoWidget"; import { NumberWidget } from "../../../../widgets/NumberWidget"; import { SearchRegexWidget } from "../../../../widgets/SearchRegexWidget"; import { TimeDatePickerWidget } from "../../../../widgets/timedatepickerwidget/TimeDatePickerWidget"; import { TreeWidget } from "../../../../widgets/treewidget/TreeWidget"; import { SortListDataProvider, SortTreeDataProvider, SortValuesListDataProvider } from "../../../../datasources/DataProviders"; import { NoOpListDataProvider, NoOpAutocompleteProvider, NoOpTreeDataProvider } from "../../../../datasources/NoOpDataProviders"; import { SparqlListDataProvider, SparqlAutocompleDataProvider, SparqlTreeDataProvider, SparqlValuesListDataProvider } from "../../../../datasources/SparqlDataProviders"; import { RDFS, SKOS, SparqlHandlerFactory } from "rdf-shacl-commons"; /** * Inversion of coupling : we don't want to depend on ISettings as this class is meant to be reused * elsewhere than in Sparnatural, hence we define our own interface of what we depend on. */ export class WidgetFactorySettings { } export class WidgetFactory { constructor(parentComponent, specProvider, settings, catalog) { _WidgetFactory_instances.add(this); this.parentComponent = parentComponent; this.specProvider = specProvider; this.settings = settings; this.catalog = catalog; // how to handle / execute a SPARQL query this.sparqlHandlerFactory = new SparqlHandlerFactory(this.settings.language, this.settings.localCacheDataTtl, this.settings.customization.headers, this.settings.customization.sparqlHandler, this.catalog); // how to post-process the generated SPARQL after it is constructed and before it is send this.sparqlPostProcessor = { semanticPostProcess: (sparql) => { // also add prefixes for (let key in this.settings.sparqlPrefixes) { sparql = sparql.replace("SELECT ", "PREFIX " + key + ": <" + this.settings.sparqlPrefixes[key] + "> \nSELECT "); } return this.specProvider.expandSparql(sparql, this.settings.sparqlPrefixes); } }; } /** * Creates a widget for the specified criteria subject / predicate / object * * @param startClassVal the type + variable name of the subject * @param objectPropVal the type + variable name of the property * @param endClassVal the type + variable name of the object * @returns the widget component to be displayed */ buildWidget(startClassVal, objectPropVal, endClassVal) { let property = this.specProvider.getProperty(objectPropVal.type); // read the widgetType from the config const widgetType = property.getPropertyType(endClassVal.type); switch (widgetType) { case Config.LITERAL_LIST_PROPERTY: case Config.LIST_PROPERTY: // determine custom datasource var datasource = property.getDatasource(); if (datasource == null) { // datasource still null // if a default endpoint was provided, provide default datasource if (this.settings.endpoints || this.settings.catalog) { // if there are some values specified in the config with sh:in, use a values datasource if (property.getValues()) { datasource = { queryTemplate: Datasources.QUERY_STRINGS_BY_QUERY_TEMPLATE.get(Datasources.QUERY_LIST_LABEL_VALUES_ALPHA), labelPath: "<" + RDFS.LABEL.value + ">|<" + SKOS.PREF_LABEL.value + ">" }; } // if there is a default label property on the end class, use it to populate the dropdown else if (this.specProvider.getEntity(endClassVal.type).getDefaultLabelProperty()) { let defautlDatasource = property.hasQualifiedValueShapeRange() ? Datasources.QUERY_LIST_LABEL_WITH_RANGE_ALPHA : Datasources.QUERY_LIST_LABEL_ALPHA; datasource = { queryTemplate: Datasources.QUERY_STRINGS_BY_QUERY_TEMPLATE.get(defautlDatasource), labelProperty: this.specProvider.getEntity(endClassVal.type).getDefaultLabelProperty(), }; // if there is no datasource and no default label on the end class, but we can guess the end class could be skos:Concept, // use a skos:prefLabel datasource } else if (this.specProvider.getEntity(endClassVal.type).couldBeSkosConcept()) { let defautlDatasource = property.hasQualifiedValueShapeRange() ? Datasources.QUERY_LIST_LABEL_WITH_RANGE_ALPHA : Datasources.QUERY_LIST_LABEL_ALPHA; datasource = { queryTemplate: Datasources.QUERY_STRINGS_BY_QUERY_TEMPLATE.get(defautlDatasource), labelProperty: SKOS.PREF_LABEL.value, }; } else { // that datasource can work indifferently with URIs or Literals datasource = Datasources.DATASOURCES_CONFIG.get( // better use alphabetical ordering first since URIs will be segregated in the "h" letter and not mixed // Datasources.LIST_URI_OR_LITERAL_ALPHA_WITH_COUNT Datasources.LIST_URI_OR_LITERAL_ALPHA); } } } let listDataProvider = new NoOpListDataProvider(); if (datasource != null) { if (property.getValues()) { // if there was some fixed values specified in the config, use a ValuesListDataProvider listDataProvider = new SparqlValuesListDataProvider( // endpoint URL this.sparqlHandlerFactory.buildSparqlHandler(datasource.sparqlEndpointUrl != null ? [datasource.sparqlEndpointUrl] : this.settings.endpoints), new ValuesListSparqlTemplateQueryBuilder( // sparql query (with labelPath interpreted) __classPrivateFieldGet(this, _WidgetFactory_instances, "m", _WidgetFactory_getFinalQueryString).call(this, datasource), // sparqlPostProcessor this.sparqlPostProcessor)); // if we need to sort things, add an explicit wrapper around the data provider if (!(datasource.noSort == true)) { listDataProvider = new SortValuesListDataProvider(listDataProvider); } } else { // if we have a datasource, possibly the default one, provide a config based // on a SparqlTemplate, otherwise use the handler provided listDataProvider = new SparqlListDataProvider( // endpoint URL this.sparqlHandlerFactory.buildSparqlHandler(datasource.sparqlEndpointUrl != null ? [datasource.sparqlEndpointUrl] : this.settings.endpoints), new ListSparqlTemplateQueryBuilder( // sparql query (with labelPath interpreted) __classPrivateFieldGet(this, _WidgetFactory_instances, "m", _WidgetFactory_getFinalQueryString).call(this, datasource), // sparqlPostProcessor this.sparqlPostProcessor)); // if we need to sort things, add an explicit wrapper around the data provider if (!(datasource.noSort == true)) { listDataProvider = new SortListDataProvider(listDataProvider); } } } // create the configuration object : use the default configuration, then the generated data provider, then overwrite with // what is set in the provided configuration object for the corresponding section let listConfig = { ...ListWidget.defaultConfiguration, ...{ dataProvider: listDataProvider, values: this.specProvider.getProperty(objectPropVal.type).getValues(), }, ...this.settings.customization?.list }; // init data provider listConfig.dataProvider.init(this.settings.language, this.settings.defaultLanguage, this.settings.typePredicate); return new ListWidget(this.parentComponent, listConfig, startClassVal, objectPropVal, endClassVal); case Config.AUTOCOMPLETE_PROPERTY: // to be passed in anonymous functions var theSpecProvider = this.specProvider; // determine custom datasource var datasource = this.specProvider.getProperty(objectPropVal.type).getDatasource(); if (datasource == null) { // datasource still null // if a default endpoint was provided, provide default datasource if (this.settings.endpoints) { if (this.specProvider.getEntity(endClassVal.type).isLiteralEntity()) { datasource = Datasources.DATASOURCES_CONFIG.get(Datasources.SEARCH_LITERAL_CONTAINS); } else { // if there is a default label property on the end class, use it to search in the autocomplete if (this.specProvider.getEntity(endClassVal.type).getDefaultLabelProperty()) { datasource = { queryTemplate: Datasources.QUERY_STRINGS_BY_QUERY_TEMPLATE.get(Datasources.QUERY_SEARCH_LABEL_CONTAINS), labelProperty: this.specProvider.getEntity(endClassVal.type).getDefaultLabelProperty(), }; } else { // otherwise just search on the URI datasource = Datasources.DATASOURCES_CONFIG.get(Datasources.SEARCH_URI_CONTAINS); } } } } let autocompleteDataProvider = new NoOpAutocompleteProvider(); if (datasource != null) { // build a SPARQL data provider function using the SPARQL query of the datasource autocompleteDataProvider = new SparqlAutocompleDataProvider( // endpoint URL this.sparqlHandlerFactory.buildSparqlHandler(datasource.sparqlEndpointUrl != null ? [datasource.sparqlEndpointUrl] : this.settings.endpoints), new AutocompleteSparqlTemplateQueryBuilder( // sparql query (with labelPath interpreted) __classPrivateFieldGet(this, _WidgetFactory_instances, "m", _WidgetFactory_getFinalQueryString).call(this, datasource), // sparqlPostProcessor this.sparqlPostProcessor)); } // create the configuration object : use the default data provider, then the default configuration, then overwrite with is set in // the provided configuration object for the corresponding section let autocompleteConfig = { ...AutoCompleteWidget.defaultConfiguration, ...{ dataProvider: autocompleteDataProvider }, ...this.settings.customization?.autocomplete }; // init data provider autocompleteConfig.dataProvider.init(this.settings.language, this.settings.defaultLanguage, this.settings.typePredicate); return new AutoCompleteWidget(this.parentComponent, autocompleteConfig, startClassVal, objectPropVal, endClassVal); break; case Config.VIRTUOSO_SEARCH_PROPERTY: case Config.GRAPHDB_SEARCH_PROPERTY: case Config.STRING_EQUALS_PROPERTY: case Config.SEARCH_PROPERTY: let configuration = { widgetType: widgetType }; return new SearchRegexWidget(configuration, this.parentComponent, startClassVal, objectPropVal, endClassVal); break; case Config.TIME_PROPERTY_YEAR: return new TimeDatePickerWidget(this.parentComponent, "year", startClassVal, objectPropVal, endClassVal, this.specProvider); break; case Config.TIME_PROPERTY_DATE: return new TimeDatePickerWidget(this.parentComponent, "day", startClassVal, objectPropVal, endClassVal, this.specProvider); break; case Config.TIME_PROPERTY_PERIOD: console.warn(Config.TIME_PROPERTY_PERIOD + " is not implement yet"); break; case Config.NON_SELECTABLE_PROPERTY: return new NoWidget(this.parentComponent); break; case Config.BOOLEAN_PROPERTY: let booleanConfig = { existNotExist: !this.specProvider.getEntity(endClassVal.type).isLiteralEntity() }; return new BooleanWidget(this.parentComponent, booleanConfig, startClassVal, objectPropVal, endClassVal); break; case Config.TREE_PROPERTY: var theSpecProvider = this.specProvider; // determine custom roots datasource var treeRootsDatasource = this.specProvider.getProperty(objectPropVal.type).getTreeRootsDatasource(); if (treeRootsDatasource == null) { // datasource still null // if a default endpoint was provided, provide default datasource if (this.settings.endpoints) { treeRootsDatasource = Datasources.DATASOURCES_CONFIG.get(Datasources.TREE_ROOT_SKOSTOPCONCEPT); } } // determine custom children datasource var treeChildrenDatasource = this.specProvider.getProperty(objectPropVal.type).getTreeChildrenDatasource(); if (treeChildrenDatasource == null) { // datasource still null // if a default endpoint was provided, provide default datasource if (this.settings.endpoints) { treeChildrenDatasource = Datasources.DATASOURCES_CONFIG.get(Datasources.TREE_CHILDREN_SKOSNARROWER); } } let treeDataProvider = new NoOpTreeDataProvider(); if (treeRootsDatasource != null && treeChildrenDatasource != null) { // if we have a datasource, possibly the default one, provide a config based // on a SparqlTemplate, otherwise use the handler provided treeDataProvider = new SparqlTreeDataProvider( // endpoint URL // we read it on the roots datasource this.sparqlHandlerFactory.buildSparqlHandler(treeRootsDatasource.sparqlEndpointUrl != null ? [treeRootsDatasource.sparqlEndpointUrl] : this.settings.endpoints), new TreeSparqlTemplateQueryBuilder( // sparql query (with labelPath interpreted) __classPrivateFieldGet(this, _WidgetFactory_instances, "m", _WidgetFactory_getFinalQueryString).call(this, treeRootsDatasource), __classPrivateFieldGet(this, _WidgetFactory_instances, "m", _WidgetFactory_getFinalQueryString).call(this, treeChildrenDatasource), // sparqlPostProcessor this.sparqlPostProcessor)); } // create the configuration object : use the default data provider, then the default configuration, then overwrite with is set in // the provided configuration object for the corresponding section let treeConfig = { ...TreeWidget.defaultConfiguration, ...{ dataProvider: treeDataProvider, maxSelectedItems: this.settings.maxOr }, ...this.settings.customization?.tree }; // wrap inside a sort data provider if needed if (!(treeChildrenDatasource.noSort == true)) { treeConfig.dataProvider = new SortTreeDataProvider(treeConfig.dataProvider); } // init data provider treeConfig.dataProvider.init(this.settings.language, this.settings.defaultLanguage, this.settings.typePredicate); return new TreeWidget(this.parentComponent, treeConfig, startClassVal, objectPropVal, endClassVal); case Config.MAP_PROPERTY: let mapConfig = { ...MapWidget.defaultConfiguration, ...this.settings.customization?.map }; return new MapWidget(mapConfig, this.parentComponent, startClassVal, objectPropVal, endClassVal).render(); case Config.NUMBER_PROPERTY: let thisNumberConfig = { min: this.specProvider.getProperty(objectPropVal.type).getMinValue(), max: this.specProvider.getProperty(objectPropVal.type).getMaxValue(), }; let numberConfig = { ...NumberWidget.defaultConfiguration, ...thisNumberConfig, ...this.settings.customization?.number }; return new NumberWidget(this.parentComponent, numberConfig, startClassVal, objectPropVal, endClassVal).render(); default: throw new Error(`WidgetType for ${widgetType} not recognized`); } } } _WidgetFactory_instances = new WeakSet(), _WidgetFactory_getFinalQueryString = function _WidgetFactory_getFinalQueryString(datasource) { if (datasource.queryString != null) { return datasource.queryString; } else { var sparql = datasource.queryTemplate; if (datasource.labelPath != null || datasource.labelProperty) { var theLabelPath = datasource.labelPath ? datasource.labelPath : "<" + datasource.labelProperty + ">"; var reLabelPath = new RegExp("\\$labelPath", "g"); sparql = sparql.replace(reLabelPath, theLabelPath); } if (datasource.childrenPath != null || datasource.childrenProperty) { var theChildrenPath = datasource.childrenPath ? datasource.childrenPath : "<" + datasource.childrenProperty + ">"; var reChildrenPath = new RegExp("\\$childrenPath", "g"); sparql = sparql.replace(reChildrenPath, theChildrenPath); } return sparql; } }; //# sourceMappingURL=WidgetFactory.js.map