Skip to content

Instantly share code, notes, and snippets.

@metruzanca
Last active July 20, 2023 23:04
Show Gist options
  • Save metruzanca/7e6c8e4fe0c5e971b9e239355a691a7b to your computer and use it in GitHub Desktop.
Save metruzanca/7e6c8e4fe0c5e971b9e239355a691a7b to your computer and use it in GitHub Desktop.
The namespace API had a good way to do this. Couldn't find an easy way to do this.
// Internal type correctness is not the goal. The goal is good DX building out queriesx
export class QueryBuilder {
private collection: CollectionReference<DocumentData, DocumentData>
constructor(path: string) {
this.collection = collection(firestore, path)
}
private where: QueryFieldFilterConstraint[] = []
filter(fieldPath: string | FieldPath, opStr: WhereFilterOp, value: unknown) {
this.where.push(where(fieldPath, opStr, value))
return this
}
private after: QueryStartAtConstraint | undefined
startAfter(doc: QueryDocumentSnapshot<DocumentData, DocumentData>) {
this.after = startAfter(doc)
return this
}
private limit: QueryLimitConstraint | undefined
limitTo(pageCount: number) {
this.limit = limit(pageCount)
return this
}
async getDocs() {
let parts = [this.collection, ...this.where, this.after, this.limit]
parts = parts.filter(Boolean)
// eslint-disable-next-line
// @ts-ignore I CBA to write the type for parts
const theQuery = query(...parts)
return (await getDocs(theQuery)) as QuerySnapshot<DocumentData, DocumentData>
}
}
// Example
// Keep this ref somewhere elsewhere
let last: QueryDocumentSnapshot<DocumentData, DocumentData> | undefined;
const qb = new QueryBuilder('/posts/')
if (tags.length) qb.filter('tags', 'array-contains-any', tags)
if (author) qb.filter('author', '==', author)
if (last) qb.startAfter(last)
qb.limitTo(25)
const snapshots = await qb.getDocs();
last = snapshots.docs[snapshots.docs.length - 1];
// do soemthing with snapshots
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment