Skip to content

Commit

Permalink
add back in fetchFromAllDatasets middlewares
Browse files Browse the repository at this point in the history
  • Loading branch information
GeorgeGoodall committed Jan 16, 2025
1 parent 03d581a commit 84c2bc9
Showing 1 changed file with 109 additions and 0 deletions.
109 changes: 109 additions & 0 deletions src/middleware/middleware.builders.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ import datasette from '../services/datasette.js'
import * as v from 'valibot'
import { errorTemplateContext, MiddlewareError } from '../utils/errors.js'

import { dataSubjects } from '../utils/utils.js'

const availableDatasets = Object.values(dataSubjects).flatMap((dataSubject) =>
(dataSubject.dataSets || [])
.filter((dataset) => dataset.available)
.map((dataset) => dataset.value)
)

export const FetchOptions = {
/**
* Use 'dataset' from requets params.
Expand Down Expand Up @@ -117,6 +125,89 @@ export async function fetchManyFn (req, res, next) {
}
}

/**
* Fetches one result from all available datasets.
*
* This function runs a query on each available dataset, catches any errors that may occur,
* and then compiles the results into a single object. The result object is then attached to
* the request object.
*
* @async
* @function fetchOneFromAllDatasetsFn
* @param {Object} req - The request object.
* @param {Object} req.params - Route parameters.
* @param {string} req.originalUrl - The original URL of the request.
* @param {Object} req[this.result] - A property to store the result of the query.
* @param {string} req.handlerName - A property to store the name of the handler.
* @param {function} req.query - A function to construct a query based on the request parameters.
* @param {Object} res - The response object.
* @param {Function} next - The next middleware function in the stack.
* @throws {Error} If any of the queries fail.
* @memberof middleware
*/
export async function fetchOneFromAllDatasetsFn (req, res, next) {
try {
const query = this.query({ req, params: req.params })
const promises = availableDatasets.map((dataset) => {
return datasette.runQuery(query, dataset).catch(error => {
logger.error('Query failed for dataset', { dataset, errorMessage: error.message, errorStack: error.stack, type: types.DataFetch })
throw error
})
})
const result = await Promise.all(promises)
req[this.result] = Object.fromEntries(
result.reduce((acc, { formattedData }, i) => {
if (formattedData.length > 0) {
acc.push([availableDatasets[i], formattedData[0]])
}
return acc
}, [])
)
logger.debug({ type: types.DataFetch, message: 'fetchOneFromAllDatasets', resultKey: this.result })
next()
} catch (error) {
logger.debug('fetchOneFromAllDatasetsFn: failed', { type: types.DataFetch, errorMessage: error.message, endpoint: req.originalUrl, resultKey: this.result })
req.handlerName = `fetching '${this.result}'`
next(error)
}
}

/**
* Fetches data from all available datasets and stores the result in the request object.
*
* @async
* @function fetchManyFromAllDatasetsFn
* @param {Object} req - The request object.
* @param {string} req.params - The URL parameters for the request.
* @param {Object} req[this.result] - Property of the request object where the result will be stored.
* @param {Object} res - The response object.
* @param {Function} next - The next middleware function in the chain.
*
* @throws {Error} If an error occurs while fetching data from any of the datasets.
*/
export async function fetchManyFromAllDatasetsFn (req, res, next) {
try {
const query = this.query({ req, params: req.params })
const promises = availableDatasets.map((dataset) => {
return datasette.runQuery(query, dataset).catch(error => {
logger.error('Query failed for dataset', { dataset, errorMessage: error.message, errorStack: error.stack, type: types.DataFetch })
throw error
})
})
const result = await Promise.all(promises)
req[this.result] = Object.fromEntries(
result.filter(({ formattedData }) => formattedData.length > 0)
.map(({ formattedData }, i) => [availableDatasets[i], formattedData])
)
logger.debug({ type: types.DataFetch, message: 'fetchManyFromAllDatasets', resultKey: this.result })
next()
} catch (error) {
logger.debug('fetchManyFromAllDatasetsFn: failed', { type: types.DataFetch, errorMessage: error.message, endpoint: req.originalUrl, resultKey: this.result })
req.handlerName = `fetching '${this.result}'`
next(error)
}
}

/**
* Middleware. Does a conditional fetch. Optionally invokes `else` if condition is false.
*
Expand Down Expand Up @@ -181,6 +272,24 @@ export function fetchMany (context) {
return fetchManyFn.bind(context)
}

/**
* Fetches a single record from each dataset databases and stores them in `req` under key specified by `result` entry.
*
* @param {{query: ({req, params}) => object, result: string, dataset?: FetchParams | (req) => string}} context
*/
export function fetchOneFromAllDatasets (context) {
return fetchOneFromAllDatasetsFn.bind(context)
}

/**
* Fetches a collection of records from all dataset databases and stores them in `req` under key specified by `result` entry.
*
* @param {{query: ({req, params}) => object, result: string, dataset?: FetchParams | (req) => string}} context
*/
export function fetchManyFromAllDatasets (context) {
return fetchManyFromAllDatasetsFn.bind(context)
}

/**
* Looks up schema for name in @{link templateSchema} (defaults to any()), validates and renders the template.
*
Expand Down

0 comments on commit 84c2bc9

Please sign in to comment.