From 51d29b4f5b24e8a87bf7340ad5163c81d9d456f5 Mon Sep 17 00:00:00 2001 From: esikkala <esko.ikkala@aalto.fi> Date: Wed, 14 Nov 2018 17:19:55 +0200 Subject: [PATCH] Refactor facet functions --- src/client/actions/index.js | 3 +- src/client/components/FacetDialog.js | 10 ++---- src/client/components/ResultTable.js | 1 + src/client/components/Tree.js | 15 ++++---- src/client/containers/MapApp.js | 2 ++ src/client/epics/index.js | 9 ++--- src/client/reducers/facet.js | 26 ++++++++++++++ src/client/reducers/search.js | 27 --------------- src/server/index.js | 5 ++- src/server/sparql/Datasets.js | 46 +++++++++++++++++++++++++ src/server/sparql/Manuscripts.js | 51 ++-------------------------- 11 files changed, 97 insertions(+), 98 deletions(-) diff --git a/src/client/actions/index.js b/src/client/actions/index.js index 9ffc6c5f..c1dc88f9 100644 --- a/src/client/actions/index.js +++ b/src/client/actions/index.js @@ -151,9 +151,8 @@ export const fetchPlaceFailed = (error) => ({ }); // Facet -export const fetchFacet = (property) => ({ +export const fetchFacet = () => ({ type: FETCH_FACET, - property }); export const updateFacet = ({ facetValues }) => ({ type: UPDATE_FACET, diff --git a/src/client/components/FacetDialog.js b/src/client/components/FacetDialog.js index 4d4b2572..94925d6c 100644 --- a/src/client/components/FacetDialog.js +++ b/src/client/components/FacetDialog.js @@ -40,14 +40,9 @@ class FacetDialog extends React.Component { } } - handleClickOpen = () => { - this.props.fetchFacet(this.props.property); - this.setState({ open: true }); - }; + handleClickOpen = () => this.setState({ open: true }); - handleClose = () => { - this.setState({ open: false }); - }; + handleClose = () => this.setState({ open: false }); render() { const { classes, propertyLabel, facet } = this.props; @@ -75,6 +70,7 @@ class FacetDialog extends React.Component { : <Tree data={facet.facetValues.creationPlace} + fetchFacet={this.props.fetchFacet} updateFilter={this.props.updateFilter} />} </DialogContent> diff --git a/src/client/components/ResultTable.js b/src/client/components/ResultTable.js index d3c731ff..b9c74e0e 100644 --- a/src/client/components/ResultTable.js +++ b/src/client/components/ResultTable.js @@ -57,6 +57,7 @@ class ResultTable extends React.Component { componentDidMount = () => { this.props.fetchResults(); this.props.fetchManuscripts(0); + this.props.fetchFacet(); } idRenderer = (row) => { diff --git a/src/client/components/Tree.js b/src/client/components/Tree.js index bbb5077f..9426a552 100644 --- a/src/client/components/Tree.js +++ b/src/client/components/Tree.js @@ -37,12 +37,14 @@ class Tree extends Component { }; } - handleCheckboxChange = name => event => { - console.log(name) - console.log(event.target.checked) - // this.props.updateFilter({ - // - // }) + handleCheckboxChange = name => () => { + //console.log(name) + //console.log(event.target.checked) + this.props.updateFilter({ + property: 'creationPlace', + value: name + }); + this.props.fetchFacet(); }; render() { @@ -170,6 +172,7 @@ class Tree extends Component { Tree.propTypes = { classes: PropTypes.object.isRequired, data: PropTypes.array.isRequired, + fetchFacet: PropTypes.func.isRequired, updateFilter: PropTypes.func.isRequired, }; diff --git a/src/client/containers/MapApp.js b/src/client/containers/MapApp.js index 84dc5750..60d44911 100644 --- a/src/client/containers/MapApp.js +++ b/src/client/containers/MapApp.js @@ -89,6 +89,8 @@ let MapApp = (props) => { // browser // error, + // console.log(props.facet) + return ( <div className={classes.root}> <div className={classes.appFrame}> diff --git a/src/client/epics/index.js b/src/client/epics/index.js index 0f6bca26..083ca292 100644 --- a/src/client/epics/index.js +++ b/src/client/epics/index.js @@ -1,6 +1,6 @@ import { ajax } from 'rxjs/ajax'; -import { mergeMap, map } from 'rxjs/operators'; +import { mergeMap, map, withLatestFrom } from 'rxjs/operators'; import { combineEpics, ofType } from 'redux-observable'; import { updateManuscripts, @@ -57,9 +57,10 @@ const getPlace = action$ => action$.pipe( const getFacet = action$ => action$.pipe( ofType(FETCH_FACET), - mergeMap((action) => { - const searchUrl = apiUrl + 'facet'; - const requestUrl = `${searchUrl}?property=${action.property}`; + mergeMap(() => { + const requestUrl = `${apiUrl}facet`; + //const facetFilters = state$.getState().facet.facetFilters; + //let str = Object.entries(facetFilters).map(([key, set]) => `${key}=${Array.from(set)}`).join('&'); return ajax.getJSON(requestUrl).pipe( map(response => updateFacet({ facetValues: response })) ); diff --git a/src/client/reducers/facet.js b/src/client/reducers/facet.js index 1c7d0cb1..f02b7464 100644 --- a/src/client/reducers/facet.js +++ b/src/client/reducers/facet.js @@ -1,6 +1,7 @@ import { FETCH_FACET, UPDATE_FACET, + UPDATE_FILTER } from '../actions'; export const INITIAL_STATE = { @@ -16,6 +17,10 @@ export const INITIAL_STATE = { creationPlace: [], author: [] }, + facetFilters: { + creationPlace: new Set(), + author: new Set(), + }, fetchingFacet : false }; @@ -29,9 +34,30 @@ const facet = (state = INITIAL_STATE, action) => { facetValues: action.facetValues, fetchingFacet: false }; + case UPDATE_FILTER: + return updateFilter(state, action); default: return state; } }; +const updateFilter = (state, action) => { + const { property, value } = action.filter; + let nSet = state.facetFilters[property]; + if (nSet.has(value)) { + nSet.delete(value); + } else { + nSet.add(value); + } + const newFilter = updateObject(state.filters, { [property]: nSet }); + return updateObject(state, { facetFilters: newFilter }); +}; + +const updateObject = (oldObject, newValues) => { + // Encapsulate the idea of passing a new object as the first parameter + // to Object.assign to ensure we correctly copy data instead of mutating + //console.log(Object.assign({}, oldObject, newValues)); + return Object.assign({}, oldObject, newValues); +}; + export default facet; diff --git a/src/client/reducers/search.js b/src/client/reducers/search.js index 3d069181..b5002020 100644 --- a/src/client/reducers/search.js +++ b/src/client/reducers/search.js @@ -15,7 +15,6 @@ import { CLEAR_PLACES, UPDATE_PLACE, SORT_RESULTS, - UPDATE_FILTER } from '../actions'; export const INITIAL_STATE = { @@ -34,10 +33,6 @@ export const INITIAL_STATE = { 'selected': false }, }, - filters: { - creationPlace: new Set(), - author: new Set(), - }, suggestions: [], suggestionsQuery: '', fetchingSuggestions: false, @@ -132,10 +127,7 @@ const search = (state = INITIAL_STATE, action) => { 'places': {}, fetchingPlaces: false }; - case UPDATE_FILTER: - return updateFilter(state, action); case SORT_RESULTS: - //console.log(action) return { ...state, sortBy: action.options.sortBy, @@ -146,23 +138,4 @@ const search = (state = INITIAL_STATE, action) => { } }; -const updateFilter = (state, action) => { - const { property, value } = action.filter; - let nSet = state.filters[property]; - if (nSet.has(value)) { - nSet.delete(value); - } else { - nSet.add(value); - } - const newFilter = updateObject(state.filters, { [property]: nSet }); - return updateObject(state, { filters: newFilter }); -}; - -const updateObject = (oldObject, newValues) => { - // Encapsulate the idea of passing a new object as the first parameter - // to Object.assign to ensure we correctly copy data instead of mutating - //console.log(Object.assign({}, oldObject, newValues)); - return Object.assign({}, oldObject, newValues); -}; - export default search; diff --git a/src/server/index.js b/src/server/index.js index 196dfa4b..c74b02a7 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -85,13 +85,12 @@ app.get('/places/:placeId?', (req, res) => { }); app.get('/facet', (req, res) => { - const property = req.query.property; - return getFacet(property).then((data) => { + return getFacet().then((data) => { const facetValues = { creationPlace: data, author: [] }; - //console.log(data); + // console.log(data); res.json(facetValues); }) .catch((err) => { diff --git a/src/server/sparql/Datasets.js b/src/server/sparql/Datasets.js index 816649a8..5a4e477a 100644 --- a/src/server/sparql/Datasets.js +++ b/src/server/sparql/Datasets.js @@ -305,6 +305,52 @@ module.exports = { #} } `, + 'facetQuery': ` + PREFIX skos: <http://www.w3.org/2004/02/skos/core#> + PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> + PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> + PREFIX crm: <http://www.cidoc-crm.org/cidoc-crm/> + PREFIX owl: <http://www.w3.org/2002/07/owl#> + PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> + PREFIX text: <http://jena.apache.org/text#> + PREFIX dct: <http://purl.org/dc/terms/> + PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#> + PREFIX sch: <http://schema.org/> + PREFIX geosparql: <http://www.opengis.net/ont/geosparql#> + PREFIX frbroo: <http://erlangen-crm.org/efrbroo/> + PREFIX mmm-schema: <http://ldf.fi/mmm/schema/> + SELECT DISTINCT ?cnt ?facet_text ?value ?parent + WHERE { + SELECT DISTINCT ?cnt ?value ?facet_text ?parent { + { SELECT DISTINCT (count(DISTINCT ?id) as ?cnt) ?value ?parent + { + ?id a frbroo:F4_Manifestation_Singleton . + ?id skos:prefLabel ?name . + ?id ^frbroo:R18_created/crm:P7_took_place_at ?value . + OPTIONAL { ?value mmm-schema:parent ?parent } + } + GROUP BY ?value ?parent + } + FILTER(BOUND(?value)) BIND(COALESCE(?value, <http://ldf.fi/NONEXISTENT_URI>) AS ?labelValue) + OPTIONAL { ?labelValue skos:prefLabel ?lbl . + FILTER(langMatches(lang(?lbl), "fi")) . } + OPTIONAL { ?labelValue rdfs:label ?lbl . + FILTER(langMatches(lang(?lbl), "fi")) . } + OPTIONAL { ?labelValue skos:prefLabel ?lbl . + FILTER(langMatches(lang(?lbl), "en")) . } + OPTIONAL { ?labelValue rdfs:label ?lbl . + FILTER(langMatches(lang(?lbl), "en")) . } + OPTIONAL { ?labelValue skos:prefLabel ?lbl . + FILTER(langMatches(lang(?lbl), "sv")) . } + OPTIONAL { ?labelValue rdfs:label ?lbl . + FILTER(langMatches(lang(?lbl), "sv")) . } + OPTIONAL { ?labelValue skos:prefLabel ?lbl . + FILTER(langMatches(lang(?lbl), "")) . } + OPTIONAL { ?labelValue rdfs:label ?lbl . + FILTER(langMatches(lang(?lbl), "")) . } + BIND(COALESCE(?lbl, IF(!ISURI(?value), ?value, "")) AS ?facet_text) } + } + `, 'tgn': { // Getty LOD documentation: // http://vocab.getty.edu/queries#Places_by_Type diff --git a/src/server/sparql/Manuscripts.js b/src/server/sparql/Manuscripts.js index 0cdee0db..faa581b6 100644 --- a/src/server/sparql/Manuscripts.js +++ b/src/server/sparql/Manuscripts.js @@ -37,8 +37,8 @@ export const getPlace = (id) => { return sparqlSearchEngine.doSearch(placeQuery, endpoint, makeObjectList); }; -export const getFacet = (property) => { - const { endpoint } = datasetConfig['mmm']; +export const getFacet = () => { + const { endpoint, facetQuery } = datasetConfig['mmm']; // console.log(facetQuery) return sparqlSearchEngine.doSearch(facetQuery, endpoint, mapFacet); }; @@ -53,50 +53,3 @@ const generateFilter = (filterObj) => { } return filterStr; }; - -const facetQuery = ` - PREFIX skos: <http://www.w3.org/2004/02/skos/core#> - PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> - PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> - PREFIX crm: <http://www.cidoc-crm.org/cidoc-crm/> - PREFIX owl: <http://www.w3.org/2002/07/owl#> - PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> - PREFIX text: <http://jena.apache.org/text#> - PREFIX dct: <http://purl.org/dc/terms/> - PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#> - PREFIX sch: <http://schema.org/> - PREFIX geosparql: <http://www.opengis.net/ont/geosparql#> - PREFIX frbroo: <http://erlangen-crm.org/efrbroo/> - PREFIX mmm-schema: <http://ldf.fi/mmm/schema/> - SELECT DISTINCT ?cnt ?facet_text ?value ?parent - WHERE { - SELECT DISTINCT ?cnt ?value ?facet_text ?parent { - { SELECT DISTINCT (count(DISTINCT ?id) as ?cnt) ?value ?parent - { - ?id a frbroo:F4_Manifestation_Singleton . - ?id skos:prefLabel ?name . - ?id ^frbroo:R18_created/crm:P7_took_place_at ?value . - OPTIONAL { ?value mmm-schema:parent ?parent } - } - GROUP BY ?value ?parent - } - FILTER(BOUND(?value)) BIND(COALESCE(?value, <http://ldf.fi/NONEXISTENT_URI>) AS ?labelValue) - OPTIONAL { ?labelValue skos:prefLabel ?lbl . - FILTER(langMatches(lang(?lbl), "fi")) . } - OPTIONAL { ?labelValue rdfs:label ?lbl . - FILTER(langMatches(lang(?lbl), "fi")) . } - OPTIONAL { ?labelValue skos:prefLabel ?lbl . - FILTER(langMatches(lang(?lbl), "en")) . } - OPTIONAL { ?labelValue rdfs:label ?lbl . - FILTER(langMatches(lang(?lbl), "en")) . } - OPTIONAL { ?labelValue skos:prefLabel ?lbl . - FILTER(langMatches(lang(?lbl), "sv")) . } - OPTIONAL { ?labelValue rdfs:label ?lbl . - FILTER(langMatches(lang(?lbl), "sv")) . } - OPTIONAL { ?labelValue skos:prefLabel ?lbl . - FILTER(langMatches(lang(?lbl), "")) . } - OPTIONAL { ?labelValue rdfs:label ?lbl . - FILTER(langMatches(lang(?lbl), "")) . } - BIND(COALESCE(?lbl, IF(!ISURI(?value), ?value, "")) AS ?facet_text) } - } -`; -- GitLab