https://github.com/carmelocampos/firestore-db-orm
ORM for the database in Firestore
https://github.com/carmelocampos/firestore-db-orm
firebase firebase-db-orm firestore firestore-orm
Last synced: 5 months ago
JSON representation
ORM for the database in Firestore
- Host: GitHub
- URL: https://github.com/carmelocampos/firestore-db-orm
- Owner: CarmeloCampos
- License: mpl-2.0
- Created: 2024-06-10T04:20:41.000Z (about 2 years ago)
- Default Branch: main
- Last Pushed: 2024-07-12T06:33:16.000Z (almost 2 years ago)
- Last Synced: 2024-11-14T20:12:12.089Z (over 1 year ago)
- Topics: firebase, firebase-db-orm, firestore, firestore-orm
- Language: TypeScript
- Homepage: https://www.npmjs.com/package/firestore-db-orm
- Size: 155 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Firestore DB ORM
`firestore-db-orm` is a lightweight, TypeScript-first Object-Relational Mapper (ORM) for Google Firestore. It simplifies interactions with your Firestore database by providing an intuitive, promise-based API for common CRUD (Create, Read, Update, Delete) operations and flexible querying.
## Table of Contents
- [Features](#features)
- [Installation](#installation)
- [Instantiate the ORM](#instantiate-the-orm)
- [CRUD Operations](#crud-operations)
- [`add(data: T): Promise`](#adddata-t-promiset)
- [`get(id: string): Promise`](#getid-string-promiset--undefined)
- [`update(id: string, data: Partial): Promise`](#updateid-string-data-partialt-promisevoid)
- [`delete(id: string): Promise`](#deleteid-string-promisevoid)
- [`findOne(searchParams: SearchParams): Promise`](#findonesearchparams-searchparams-promiset--undefined)
- [Finding Multiple Documents (`finds` Method)](#finding-multiple-documents-finds-method)
- [Examples of `finds` Method](#examples-of-finds-method)
- [Advanced Usage (Future Enhancements)](#advanced-usage-future-enhancements)
- [Contributing](#contributing)
- [License](#license)
## Features
* **Type-Safe:** Leverages TypeScript for strong typing of your data models.
* **Simple API:** Easy-to-understand methods for CRUD operations.
* **Flexible Querying:** Supports various query conditions for finding documents.
* **Automatic ID Generation:** Automatically handles `id` generation for new documents (using `uuid`).
* **Promise-based:** Asynchronous operations using Promises for modern JavaScript.
## Installation
Install `firestore-db-orm` using your preferred package manager:
**bun**
```bash
bun add firestore-db-orm
```
**npm**
```bash
npm install firestore-db-orm
```
**yarn**
```bash
yarn add firestore-db-orm
```
## Instantiate the ORM
```typescript
import { initializeApp, cert } from 'firebase-admin/app';
import { getFirestore } from 'firebase-admin/firestore';
import { FirestoreORM } from "firestore-db-orm";
import type { IUser } from "./user.interface"; // Your data model interface
// Initialize Firebase Admin SDK
// Ensure you have your service account key JSON file
// (e.g., serviceAccountKey.json) in your project.
// Replace with your actual service account key path and project details.
const serviceAccount = require('./path/to/your/serviceAccountKey.json');
initializeApp({
credential: cert(serviceAccount),
// databaseURL: 'https://.firebaseio.com' // Optional: if not using default
});
// Get Firestore instance
const db = getFirestore();
// Instantiate the ORM
// Parameters:
// 1. db: The Firestore instance.
// 2. modelCollection: The name of the Firestore collection (e.g., "users").
const userORM = new FirestoreORM(db, "users");
export default userORM;
```
**Explanation:**
* **`IUser`**: This is a TypeScript interface defining the structure of your data (e.g., for a "users" collection). You should replace this with your actual data model.
* **`db`**: This is your initialized Firestore database instance. The example shows how to initialize it using `firebase-admin`. Make sure you have the `firebase-admin` package installed and configured with your Firebase project credentials.
* **`"users"`**: This string is the name of the Firestore collection where your data will be stored. Replace `"users"` with the actual name of your collection.
## CRUD Operations
The ORM provides methods for common Create, Read, Update, and Delete (CRUD) operations.
### `add(data: T): Promise`
Adds a new document to the collection. The `id` field is automatically generated (using `uuid`) and added to the data before saving.
```typescript
import userORM from "./user.orm"; // Assuming user.orm.ts is set up as shown above
import { v4 } from "uuid"; // Or use any ID generation strategy
(async () => {
try {
const newUser = await userORM.add({
// id: v4(), // ID is auto-generated, but you can pre-define if needed for your model
email: "test@example.com",
password: "securepassword123",
// Add other fields as per your IUser interface
});
console.log("New user created:", newUser);
} catch (error) {
console.error("Error adding user:", error);
}
})();
```
### `get(id: string): Promise`
Retrieves a document by its ID. Returns the document data if found, otherwise `undefined`.
```typescript
import userORM from "./user.orm";
(async () => {
try {
const userId = "some-user-id"; // Replace with an actual ID
const user = await userORM.get(userId);
if (user) {
console.log("User found:", user);
} else {
console.log("User not found.");
}
} catch (error) {
console.error("Error getting user:", error);
}
})();
```
### `update(id: string, data: Partial): Promise`
Updates an existing document with the provided data. `Partial` means you can provide only the fields you want to change.
```typescript
import userORM from "./user.orm";
(async () => {
try {
const userIdToUpdate = "some-user-id"; // Replace with an actual ID
await userORM.update(userIdToUpdate, { email: "updated.email@example.com" });
console.log("User updated successfully.");
// You can verify by getting the user
const updatedUser = await userORM.get(userIdToUpdate);
if (updatedUser) {
console.log("Updated user data:", updatedUser);
}
} catch (error) {
console.error("Error updating user:", error);
}
})();
```
### `delete(id: string): Promise`
Deletes a document by its ID.
```typescript
import userORM from "./user.orm";
(async () => {
try {
const userIdToDelete = "some-user-id"; // Replace with an actual ID
await userORM.delete(userIdToDelete);
console.log("User deleted successfully.");
// You can verify by trying to get the user
const deletedUser = await userORM.get(userIdToDelete);
if (!deletedUser) {
console.log("User confirmed deleted.");
}
} catch (error) {
console.error("Error deleting user:", error);
}
})();
```
### `findOne(searchParams: SearchParams): Promise`
Finds a single document that matches the search criteria. Returns the first matching document or `undefined`.
The `searchParams` object allows you to specify field conditions.
```typescript
import userORM from "./user.orm";
(async () => {
try {
const user = await userORM.findOne({
email: { where: "==", value: "test@example.com" },
});
if (user) {
console.log("User found by email:", user);
} else {
console.log("User with that email not found.");
}
} catch (error) {
console.error("Error finding one user:", error);
}
})();
```
## Finding Multiple Documents (`finds` Method)
The `finds(searchParams: SearchParams = {}): Promise` method allows you to retrieve multiple documents based on complex query conditions.
**`SearchParams` Type:**
The `searchParams` object is a key-value map where:
* **Key**: The field name in your document (e.g., `age`, `name`).
* **Value**: Can be one of the following:
* A direct value (e.g., `25`, `"Juan"`): This implies an "equals" (`==`) condition.
* A `SearchParam` object: `{ value: any; where: WhereFilterOp }` for specifying conditions like greater than (`>`), less than (`<`), etc. `WhereFilterOp` is a string type from Firebase (`<`, `<=`, `==`, `!=`, `>=`, `>`, `array-contains`, `in`, `not-in`, `array-contains-any`).
* An array of `SearchParam` objects: For applying multiple conditions to the same field (e.g., age > 10 AND age < 30).
### Example 1: Simple Search
Find documents where `age` is equal to 25.
```typescript
const searchParams1: SearchParams = {
age: 25,
};
const result1 = await userORM.finds(searchParams1);
console.log(result1);
```
### Example 2: Search with Simple Condition
Find documents where `age` is greater than 18.
```typescript
const searchParams2: SearchParams = {
age: {
value: 18,
where: ">",
},
};
const result2 = await userORM.finds(searchParams2);
console.log(result2);
```
### Example 3: Search with Multiple Conditions for the Same Field
Find documents where `age` is greater than 10 and less than 30.
```typescript
const searchParams3: SearchParams = {
age: [
{
value: 10,
where: ">",
},
{
value: 30,
where: "<",
},
],
};
const result3 = await userORM.finds(searchParams3);
console.log(result3);
```
### Example 4: Search with Multiple Fields and Conditions
Find documents where `age` is greater than 18 and `name` is equal to "Juan".
```typescript
const searchParams4: SearchParams = {
age: {
value: 18,
where: ">",
},
name: "Juan",
};
const result4 = await userORM.finds(searchParams4);
console.log(result4);
```
### Example 5: Search with Multiple Fields and Multiple Conditions
Find documents where `age` is within certain ranges and `name` is equal to "Ana".
```typescript
const searchParams5: SearchParams = {
age: [
{
value: 10,
where: ">",
},
{
value: 30,
where: "<",
},
],
name: "Ana",
};
const result5 = await userORM.finds(searchParams5);
console.log(result5);
```
### Example 6: Complex Search with Several Fields and Conditions
Find documents where `age` is greater than 10 and less than 30, `name` is "Pedro", and `active` is true.
```typescript
const searchParams6: SearchParams = {
age: [
{
value: 10,
where: ">",
},
{
value: 30,
where: "<",
},
],
name: "Pedro",
active: true,
};
const result6 = await userORM.finds(searchParams6);
console.log(result6);
```
## Advanced Usage (Future Enhancements)
Currently, the ORM focuses on providing straightforward CRUD operations. Future enhancements could include:
* **Transactions:** Support for Firestore transactions to perform multiple operations atomically.
* **Batch Writes:** Enabling batch operations (e.g., multiple `set`, `update`, or `delete` calls in a single request) for efficiency.
* **Custom Data Transformers:** Hooks or methods to transform data when reading from or writing to Firestore (e.g., for date conversions, encryption/decryption).
* **Real-time Listeners:** Integration with Firestore's real-time data synchronization capabilities.
If you have specific needs or ideas for advanced features, please feel free to open an issue or contribute to the project!
## Contributing
Contributions are welcome! If you'd like to contribute, please follow these steps:
1. **Fork the repository.**
2. **Create a new branch:** `git checkout -b my-feature-branch`
3. **Make your changes.**
4. **Commit your changes:** `git commit -m 'Add some feature'`
5. **Push to the branch:** `git push origin my-feature-branch`
6. **Open a pull request.**
Please make sure to update tests as appropriate and follow the existing code style.
## License
This project is licensed under the MPL-2.0 License. See the [LICENSE](LICENSE) file for details.