/firestore-fp

🔥 Functional helpers for convenient work with Firestore.

Primary LanguageTypeScriptMIT LicenseMIT

🔥 firestore-fp · Build Status npm PRs Welcome All Contributors GitHub license

Functional helpers for convenient work with Firestore.

firestore-fp example

Features

Getting started

Installation

yarn add @mobily/firestore-fp

or with npm

npm install @mobily/firestore-fp --save

Prerequisites

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 */ }))

Examples

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)

Api Reference

firestore-fp follows the official Firebase reference.

The current status is available here.

Contributors

Marcin Dziewulski
Marcin Dziewulski

💻 📖

License

The MIT License.

See LICENSE