Skip to content

Instantly share code, notes, and snippets.

@jose-almir
Created August 18, 2023 20:28
Show Gist options
  • Save jose-almir/ddd9d8d51a7078283a921a8be2e265ab to your computer and use it in GitHub Desktop.
Save jose-almir/ddd9d8d51a7078283a921a8be2e265ab to your computer and use it in GitHub Desktop.
Filtering proof of concept pure firebase
export interface Criteria {
field: string;
operation: string;
value: any;
}
import { Criteria } from "./Criteria";
import { Ordering } from "./Ordering";
import { Pagination } from "./Pagination";
import { PaginationResult } from "./PaginationResult";
export interface FilteringService<T> {
filter(criterias: Criteria[], ordering?: Ordering, pagination?: Pagination): Promise<PaginationResult<T>>;
}
import { Influencer } from "../../models/Influencer";
import { FilteringService } from "./FilteringService";
import {
CollectionReference,
Firestore,
Query,
WhereFilterOp,
} from "firebase-admin/firestore";
import { Criteria } from "./Criteria";
import { PaginationResult } from "./PaginationResult";
import { Ordering } from "./Ordering";
import { Pagination } from "./Pagination";
export class FirebaseFilteringService implements FilteringService<Influencer> {
private readonly INEQUALITY_OPERATORS = ["<", "<=", ">", ">=", "!="];
private readonly collection: CollectionReference;
constructor(collection: string, private db: Firestore) {
this.collection = this.db.collection(collection);
}
async filter<T>(
criterias: Criteria[],
ordering?: Ordering,
pagination: Pagination = { limit: 10, nextToken: null }
): Promise<PaginationResult<T>> {
let query: Query = this.collection;
const inequalityCriterias = new Set(
criterias
.filter((c) => this.INEQUALITY_OPERATORS.includes(c.operation))
.map((c) => c.field)
);
for (const field of inequalityCriterias) {
query = query.orderBy(field);
}
if (ordering) query = query.orderBy(ordering.field, ordering.direction);
for (const c of criterias) {
query = query.where(c.field, c.operation as WhereFilterOp, c.value);
}
if (pagination.nextToken) {
const nextDoc = await this.collection.doc(pagination.nextToken).get();
query = query.startAfter(nextDoc);
}
if (pagination.limit) {
query = query.limit(pagination.limit);
}
const result = await query.get();
return {
results: result.docs.map((d: any) => d.data() as T),
total: result.size,
nextToken:
result.size < pagination.limit
? null
: result.docs[result.docs.length - 1].id,
};
}
}
export interface Ordering {
field: string;
direction: "asc" | "desc";
}
export interface Pagination {
limit: number;
nextToken: string | null;
}
export interface PaginationResult<T> {
results: T[];
total: number;
nextToken: string | null;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment