Functional helpers for convenient work with Firestore.
- build complex queries with ease by combining helpers with
pipe
- improve the developer experience by defining default collection data type
- compatible with
firebase (web)
,firebase-admin (node)
andreact-native-firebase
- all functions are curried
- tiny size
yarn add @mobily/firestore-fp
or with npm
npm install @mobily/firestore-fp --save
Create a new function by using a query
factory function to consume your Firestore queries.
firebase-admin
import { firestore } from 'firebase-admin'
import { query } from '@mobily/firestore-fp'
export const q = query(firestore)
firebase
import firebase from 'firebase'
import 'firebase/firestore'
import { query } from '@mobily/firestore-fp'
export const q = query(firebase.firestore)
react-native-firebase@v6
import firestore from '@react-native-firebase/firestore'
import { query } from '@mobily/firestore-fp'
export const q = query(firestore)
If you use more than one Firebase app in your project you have to define a q
function per app:
import { firestore } from 'firebase-admin'
import { query } from '@mobily/firestore-fp'
export const q = query(() => firestore({ /* app config */ }))
Reusable where
helper.
import { collection, where, get } from '@mobily/firestore-fp'
import { q } from './utils'
interface Task {
name: string
isDone: boolean
userId: string
}
interface Message {
text: string
userId: string
}
interface Room {
name: string
}
const tasks = collection<Task>('tasks')
const messages = collection<Message>('messages')
const rooms = collection<Room>('rooms')
const userIdEq = where('userId', '==')
// return Promise<QuerySnapshot<Task>>
const takeUserTasks = (userId: string) => q(tasks, userIdEq(userId), get)
// return Promise<QuerySnapshot<Message>>
const takeUserMessages = (userId: string) => q(messages, userIdEq(userId), get)
// return Promise<QuerySnapshot<Room>>
const takeUserRooms = (userId: string) =>
q(rooms, userIdEq(userId) /* error, property 'userId' doesn't exist on type 'Room' */, get)
Combine collection
and doc
helpers.
import { collection, doc, get, update, remove, add, set, pipe } from '@mobily/firestore-fp'
import { q } from './utils'
interface Task {
name: string
isDone: boolean
userId: string
}
const tasks = collection<Task>('tasks')
const tasksDoc = (id: string) => pipe(tasks, doc(id))
// return Promise<DocumentSnapshot<Task>>
const takeTask = (id: string) => q(tasksDoc(id), get)
// return Promise<void>
const removeTask = (id: string) => q(tasksDoc(id), remove)
// return Promise<DocumentReference<Task>>
const addTask = (task: Task) => q(tasks, add(task))
// return Promise<void>
const setTask = (id: string, task: Task) =>
q(tasksDoc(id), set({ ...task, createdAt: new Date() }))
/* ⬆️ error: object literal may only specify known properties, and 'createdAt' does not exist in type 'Task' */
// return Promise<void>
const toggleTaskDone = (id: string, isDone: boolean) =>
q(tasksDoc(id), update({ isDone } /* ◀️ Partial<Task> */))
Compound queries.
import { collection, where, orderBy, limit, get, pipe } from '@mobily/firestore-fp'
import { q } from './utils'
interface Task {
name: string
isDone: boolean
userId: string
createdAt: number
}
const tasks = collection<Task>('tasks')
const whereIsDone = where('isDone', '==')
const orderByCreatedAt = orderBy('createdAt')
// return Promise<QuerySnapshot<Task>>
const takeCompletedTasks = () =>
q(tasks, whereIsDone(true), orderByCreatedAt('asc'), get)
const last10Completed = pipe(
whereIsDone(true),
orderByCreatedAt('desc'),
limit(10)
)
// return Promise<QuerySnapshot<Task>>
const takeLast10CompletedTasks = () => q(tasks, last10Completed, get)
Query subcollections.
import { collection, doc, get } from '@mobily/firestore-fp'
import { q } from './utils'
interface Room {
name: string
}
interface Message {
userId: string
text: string
}
const rooms = collection<Room>('rooms')
const messages = collection<Message>('messages')
// return Promise<QuerySnapshot<Message>>
const takeRoomMessages = (roomId: string) =>
q(rooms, doc(roomId), messages, get)
Convert data by using withConverter
.
import { O } from 'ts-toolbelt'
import { collection, withConverter, get, DataConverter } from '@mobily/firestore-fp'
import { q } from './utils'
interface Task {
name: string
isDone: boolean
userId: string
createdAt: number
}
type ConvertedTask = O.Merge<{ createdAt: Date }, Task>
const tasks = collection<Task>('tasks')
const taskConverter: DataConverter<Task, ConvertedTask> = {
toFirestore: data => data,
fromFirestore: data => {
return {
...data,
createdAt: new Date(date.createdAt),
}
},
}
// return Promise<QuerySnapshot<ConvertedTask>>
const takeAllTasks = () =>
q(tasks, withConverter(taskConverter), get)
firestore-fp
follows the official Firebase reference.
The current status is available here.
Marcin Dziewulski 💻 📖 |
The MIT License.
See LICENSE