How can I share Firestore collection path and model type mapping between TypeScript Firebase SDK and Firebase Admin SDK?
Example
Following code works, but it does not share collection path and model type mapping like { "courses": Course, "sections": Section }.
types.ts
export interface Course {
id: string;
}
export interface Section {
id: string;
}
collectionPath.ts
export const collectionPaths = {
courses: "courses",
sections: "sections",
};
orm.ts
import {
collection,
Firestore,
FirestoreDataConverter,
PartialWithFieldValue,
QueryDocumentSnapshot,
DocumentData,
} from "firebase/firestore";
import { collectionPaths } from "./collectionPaths";
import { Course, Section } from "./types";
const converter = <T>(): FirestoreDataConverter<T> => ({
toFirestore: (data: PartialWithFieldValue<T>) => data as DocumentData,
fromFirestore: (snap: QueryDocumentSnapshot) => snap.data() as T,
});
export const admin = (firestore: Firestore) => {
const dataPoint = <T>(collectionPath: string) =>
collection(firestore, collectionPath).withConverter(converter<T>());
return {
couses: dataPoint<Course>(collectionPaths.courses),
sections: dataPoint<Section>(collectionPaths.sections),
};
};
adminOrm.ts
import { firestore } from "firebase-admin";
import {
FirestoreDataConverter,
WithFieldValue,
QueryDocumentSnapshot,
DocumentData,
} from "firebase-admin/firestore";
import { collectionPaths } from "./collectionPaths";
import { Course, Section } from "./types";
const converter = <T>(): FirestoreDataConverter<T> => ({
toFirestore: (data: WithFieldValue<T>) => data as DocumentData,
fromFirestore: (snap: QueryDocumentSnapshot) => snap.data() as T,
});
export const adminOrm = (firestore: firestore.Firestore) => {
const dataPoint = <T>(collectionPath: string) =>
firestore.collection(collectionPath).withConverter(converter<T>());
return {
couses: dataPoint<Course>(collectionPaths.courses),
sections: dataPoint<Section>(collectionPaths.sections),
};
};
What I've tried
I've tried following code, but it loses ModelType for CollectionReference<ModelType>.
collectionPaths.ts
import { Course, Section } from "./types";
export class CollectionPath<T> {
path: string;
constructor(path: string) {
this.path = path;
}
}
export const collectionPaths = {
courses: new CollectionPath<Course>("courses"),
sections: new CollectionPath<Section>("sections"),
};
adminOrm.ts
import { firestore } from "firebase-admin";
import {
FirestoreDataConverter,
WithFieldValue,
QueryDocumentSnapshot,
DocumentData,
CollectionReference,
} from "firebase-admin/firestore";
import { collectionPaths } from "./collectionPaths";
const converter = <T>(): FirestoreDataConverter<T> => ({
toFirestore: (data: WithFieldValue<T>) => data as DocumentData,
fromFirestore: (snap: QueryDocumentSnapshot) => snap.data() as T,
});
export const adminOrm = (firestore: firestore.Firestore) => {
const dataPoint = <T>(collectionPath: string) =>
firestore.collection(collectionPath).withConverter(converter<T>());
return <{ [key in keyof typeof collectionPaths]: CollectionReference }>(
Object.entries(collectionPaths).reduce(
(p, [k, v]) => Object.assign(p, { [k]: dataPoint(v.path) }),
{}
)
);
};