@thisisagile/easy-mongo
Version:
Add support for MongoDB
56 lines (50 loc) • 2.15 kB
text/typescript
import { stages } from './Stages';
import { MongoGateway } from './MongoGateway';
import { Collection } from './Collection';
import { MongoProvider } from './MongoProvider';
import { lucene, SearchDefinition } from './Lucene';
import { asNumber, entries, Filter, Json, PageList, text, toPageList, tuple2 } from '@thisisagile/easy';
const { skip, take } = stages.skip;
const { replaceWith } = stages.replaceWith;
const { searchWithDef, searchMeta, facets } = lucene;
type FacetResult = { _id: string; count: number };
type Value = { label: string; value: string; count: number };
export const toFilters = (facets: unknown): Filter[] =>
entries(facets as Record<string, unknown>).map(([k, fs]) => ({
label: text(k).title.toString(),
field: k,
values: (fs as []).map((f: FacetResult) => toValue(f)),
}));
const toValue = (f: FacetResult): Value => ({ label: f._id ?? 'unknown', value: f._id ?? 'unknown', count: f.count });
export class AtlasSearchGateway extends MongoGateway {
constructor(
collection: Collection,
readonly searchDef: SearchDefinition,
readonly sortDef: Record<string, Record<string, 1 | -1>> = {},
provider: MongoProvider = collection.provider
) {
super(collection, provider);
}
query(query: Record<keyof typeof this.searchDef, string | number>): Promise<PageList<Json>> {
return tuple2(
this.aggregate(searchWithDef(query, this.searchDef), skip({ skip: (query?.skip as number) ?? 0 }), take({ take: (query?.take as number) ?? 250 })),
this.aggregate(
searchMeta(query, this.searchDef),
replaceWith({
total: '$count.total',
facets: Object.keys(facets(this.searchDef)).reduce((acc, k) => ({ ...acc, [k]: `$facet.${k}.buckets` }), {}),
})
)
)
.then(([data, meta]) => ({ data, meta: meta.first() }))
.then(({ data, meta }) =>
toPageList<Json>(data, {
total: asNumber(meta?.total, 0),
skip: asNumber(query?.skip, 0),
take: asNumber(query?.take, 250),
sorts: Object.keys(this.sortDef),
filters: toFilters(meta.facets),
})
);
}
}