Skip to content

Commit

Permalink
Add global exploration data module (#163 #354 #449 #501)
Browse files Browse the repository at this point in the history
  • Loading branch information
jgonggrijp committed Nov 10, 2021
1 parent 28c3851 commit db5b8c1
Showing 1 changed file with 88 additions and 0 deletions.
88 changes: 88 additions & 0 deletions frontend/src/global/exploration-data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { get, constant } from 'lodash';

import Model from '../core/model';
import { source, item } from '../common-rdf/ns';
import ldChannel from '../common-rdf/radio';
import userChannel from '../common-user/user-radio';
import ItemGraph from '../common-adapters/item-graph';
import SparqlSelectCollection from '../common-adapters/sparql-select-collection';
import {
countNodesQuery,
nodesByUserQuery,
randomNodesQuery,
} from '../sparql/compile-query';

// Items and sources that the user may want to explore shortly after landing,
// either because they are her own or because she may not know them yet.
// These collections are initially empty, but we will take care of this in the
// `lazyTrigger` function.
const userItems = new ItemGraph();
const randomItems = new ItemGraph();
const userSources = new ItemGraph(source());
const randomSources = new ItemGraph(source());

// Helper collections that we use to determine the total numbers of items and
// sources in the backend triple store. Eventually, they will contain just a
// single model with just a single attribute, 'tally'.
const itemTally = new SparqlSelectCollection('item');
const sourceTally = new SparqlSelectCollection('source');

// The model containing the statistics that we want to show on the landing page.
// It will be updated when the above collections are fetched.
const statistics = new Model({
totalItems: 0,
totalSources: 0,
userItems: 0,
userSources: 0,
});

// Common pattern for registering an event handler in order to update one of the
// statistics fields above.
function trackStatistic(collection, event, sourceKey, targetKey) {
collection.once(event, (payload) =>
statistics.set(targetKey, get(payload, sourceKey))
);
}

// Inside the single model in the tally collections, this is where we find the
// number we're interested in.
const tallyPath = ['attributes', 'tally', 'value'];

// Let's track those statistics!
trackStatistic(itemTally, 'add', tallyPath, 'totalItems');
trackStatistic(sourceTally, 'add', tallyPath, 'totalSources');
trackStatistic(userItems, 'update', 'length', 'userItems');
trackStatistic(userSources, 'update', 'length', 'userSources');

// Function factory that ensures a query to the backend is issued when one of
// our collections is first requested.
function lazyTrigger(collection, queryGen, onItems) {
let trigger = () => collection.sparqlQuery(queryGen(onItems));
return function() {
if (trigger) {
if (queryGen === nodesByUserQuery) {
userChannel.request('promise').then(trigger);
} else {
trigger();
}
trigger = null;
}
return collection;
}
}

// Issue one of the requests below in order to obtain one of the above
// collections, or the `statistics` model. Each of the collections has a
// `promise` property that you can await if you need it to be complete already,
// though it's probably best to just use a `CollectionView` in order to stay
// up-to-date. The `statistics` model will update 2 or 4 times; for the most
// accurate presentation, simply re-render whenever it changes.
ldChannel.reply({
'items:tally': lazyTrigger(itemTally, countNodesQuery, true),
'items:user': lazyTrigger(userItems, nodesByUserQuery, true),
'items:sample': lazyTrigger(randomItems, randomNodesQuery, true),
'sources:tally': lazyTrigger(sourceTally, countNodesQuery, false),
'sources:user': lazyTrigger(userSources, nodesByUserQuery, false),
'sources:sample': lazyTrigger(randomSources, randomNodesQuery, false),
'statistics': constant(statistics),
});

0 comments on commit db5b8c1

Please sign in to comment.