backtools
v0.4.0
Published
Collection of shared code I use across projects
Readme
Backtools
Backtools is a collection of backend code which I use across projects.
FirestoreCollection
FirestoreCollection is a type-safe wrapper for
a Firestore collection. Instances of
FirestoreCollection allow you to easily perform the following actions:
- Create a new document in the associated collection
- Find a document by its id in the associated collection
- Search for documents using queries with limits, sorting, field selection and relations
- Perform full text search on documents in a collection
- Update a document with partial data in the associated collection
- Delete a document from the associated collection
Setup
The example below demonstrates how to create a FirestoreCollection instance
import { FirestoreCollection } from "backtools/dist/firestore-collection.ts";
interface User {
readonly id: string;
readonly name: string;
readonly email: string;
readonly posts?: Post[]; // A "virtual" field that stores the posts of this user if requested in a query
}
interface Post {
readonly id: string;
readonly content: string;
readonly userId: string;
}
export const postDb = new FirestoreCollection({
modelReference: null! as Post,
collectionName: "posts",
});
export const userDb = new FirestoreCollection({
modelReference: null! as User,
collectionName: "users",
searchableKeys: ["name", "email"], // Optional list of keys on the User model whose values are used to build an index for full text search
relationResolvers: {
// The keys of "relationResolvers" are the virtual keys used in the interface
posts: async (user) => {
const [posts] = await postDb.search({
where: Filter.where("userId", "==", user.id),
});
return posts;
},
},
});Usage
After creating our collection instances we can use them in your application
import { Filter } from "firebase-admin/firestore";
import { userDb } from "path/to/user/db/instance";
async function Usages() {
// Find a user with id
const newUser = await userDb.create({
id: "user-id-here",
name: "Kwame",
email: "[email protected]",
});
// Find all users with total count
const [allUsers, userCount] = await userDb.search({});
// Search for users with name "Kwame" with associated posts
const [userResults] = await userDb.search({
where: Filter.where("name", "==", "Kwame"),
limit: 10,
offset: 0,
order: ["name", "desc"],
relationNames: ["posts"],
});
// Find a user with id
const specificUser = await userDb.find("user-id-here");
// Update a user
await userDb.create("user-id-here", {
name: "Kwame",
});
// Delete a user
await userDb.destroy("user-id-here");
}Batch Operations
batchOperations is a utility function which executes the specified operation on each item of the specified
data array, using the specified promiseStrategy (defaults to "all").
By default, promiseStrategy is set "all". Using this strategy will cause an early termination if an error occurs in a
particular batch. To prevent this behaviour, set promiseStrategy to "allSettled" which will output a warning message
to the console but still continue the operation on subsequent batches.
Usage
In the usage example below, we send a mail to each user fetched from the firestore.
import { batchOperations } from "backtools/batch-operations";
import { userDb } from "path/to/user/db/instance";
import { sendMail } from "@/service/mail";
async function Usage() {
const [users] = await userDb.search({});
await batchOperations({
data: users,
operation: async (user) => {
await sentMail({
email: user.email,
name: user.name,
content: `Hello ${user.name}\nThis is a test mail`
})
},
promiseStrategy: "allSettled", // Defaults to "all"
batchSize: 50, // Defaults to 25
sleepMs: 1500, // Amount of ms to sleep in between batches. Defaults to 1000
log: true // Outputs batch information to console. Defaults to true
})
}
