sanity
Version:
Sanity is a real-time content infrastructure with a scalable, hosted backend featuring a Graph Oriented Query Language (GROQ), asset pipelines and fast edge caches
66 lines (55 loc) • 1.94 kB
text/typescript
import {identity, sortBy, values} from 'lodash'
import {escapeField, fieldNeedsEscape} from '../../util'
import {INCLUDE_FIELDS_QUERY} from '../constants'
import {type FieldName, type Id, type Selection} from '../types'
type CombinedSelection = {
ids: Id[]
fields: FieldName[]
map: number[]
}
type Doc = {
_id: string
}
type Result = Doc[]
export function combineSelections(selections: Selection[]): CombinedSelection[] {
return values(
selections.reduce((output: {[key: string]: any}, [id, fields], index) => {
const key = sortBy(fields.join(','), identity).join('.')
if (!output[key]) {
output[key] = {fields: fields, ids: [], map: []}
}
const idx = output[key].ids.length
output[key].ids[idx] = id
output[key].map[idx] = index
return output
}, {}),
)
}
function stringifyId(id: string) {
return JSON.stringify(id)
}
const maybeEscape = (fieldName: string) =>
fieldNeedsEscape(fieldName) ? `"${fieldName}": @${escapeField(fieldName)}` : fieldName
function toSubQuery({ids, fields}: {ids: string[]; fields: string[]}) {
const allFields = [...INCLUDE_FIELDS_QUERY, ...fields]
return `*[_id in [${ids.map(stringifyId).join(',')}]][0...${ids.length}]{${allFields
.map(maybeEscape)
.join(',')}}`
}
export function toQuery(combinedSelections: CombinedSelection[]): string {
return `[${combinedSelections.map(toSubQuery).join(',')}][0...${combinedSelections.length}]`
}
export function reassemble(
queryResult: Result[],
combinedSelections: CombinedSelection[],
): (Doc | null)[] {
return queryResult.reduce((reprojected: (Doc | null)[], subResult, index) => {
const map = combinedSelections[index].map
map.forEach((resultIdx, i) => {
const id = combinedSelections[index].ids[i]
const found = subResult.find((doc) => doc._id === id)
reprojected[resultIdx] = found || null
})
return reprojected
}, [])
}