70 lines
1.8 KiB
TypeScript
70 lines
1.8 KiB
TypeScript
import {
|
|
collection,
|
|
doc,
|
|
type DocumentData,
|
|
type FirestoreDataConverter,
|
|
type QueryDocumentSnapshot,
|
|
type SnapshotOptions,
|
|
} from 'firebase/firestore';
|
|
|
|
import { db } from '@/lib/firebase';
|
|
import type { UserDocument, UserFirestoreDocument } from '@/types/firestore';
|
|
|
|
type TimestampFieldValue = {
|
|
toDate: () => Date;
|
|
};
|
|
|
|
function hasToDate(value: unknown): value is TimestampFieldValue {
|
|
return (
|
|
typeof value === 'object' &&
|
|
value !== null &&
|
|
'toDate' in value &&
|
|
typeof value.toDate === 'function'
|
|
);
|
|
}
|
|
|
|
export function mapTimestampFields<
|
|
Source extends Record<string, unknown>,
|
|
Result extends Record<string, unknown>,
|
|
>(data: Source, fields: Array<keyof Source>) {
|
|
const nextData = { ...data } as Record<string, unknown>;
|
|
|
|
for (const field of fields) {
|
|
const value = nextData[field as string];
|
|
|
|
if (hasToDate(value)) {
|
|
nextData[field as string] = value.toDate();
|
|
}
|
|
}
|
|
|
|
return nextData as Result;
|
|
}
|
|
|
|
const converter = <AppModel extends DocumentData, DbModel extends DocumentData>(
|
|
fromFirestoreMapper: (data: DbModel) => AppModel
|
|
): FirestoreDataConverter<AppModel> => ({
|
|
toFirestore: (value) => value as DocumentData,
|
|
fromFirestore: (
|
|
snapshot: QueryDocumentSnapshot,
|
|
options: SnapshotOptions
|
|
) => fromFirestoreMapper(snapshot.data(options) as DbModel),
|
|
});
|
|
|
|
const userConverter = converter<UserDocument, UserFirestoreDocument>((data) =>
|
|
mapTimestampFields<UserFirestoreDocument, UserDocument>(data, [
|
|
'createdAt',
|
|
'updatedAt',
|
|
])
|
|
);
|
|
|
|
export const collectionNames = {
|
|
users: 'users',
|
|
} as const;
|
|
|
|
export const usersCollectionRef = collection(db, collectionNames.users);
|
|
|
|
export const usersCollection = usersCollectionRef.withConverter(userConverter);
|
|
|
|
export const userDoc = (uid: string) => doc(usersCollection, uid);
|
|
export const userDocRef = (uid: string) => doc(usersCollectionRef, uid);
|