Skip to content

Commit 95690de

Browse files
committed
Added Firestore implementation
1 parent d0a3cd9 commit 95690de

File tree

9 files changed

+152
-49
lines changed

9 files changed

+152
-49
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ React Firebase Admin is our in-house admin dashboard boilerplate, used in many o
6464
- PWA ready thanks to CRA and Firebase
6565
- Multi-tenancy
6666
- Internationalization (English/Spanish)
67+
- Interface to choose between Real Time Database and Firestore
6768

6869
## Tech Stack
6970

@@ -88,6 +89,7 @@ React Firebase Admin is our in-house admin dashboard boilerplate, used in many o
8889
- [Format.js](https://formatjs.io/) (★ 11.7k) libraries for internationalization (see [docs](https://formatjs.io/docs/basic-internationalization-principles)).
8990
- [date-fns](https://date-fns.org/) (★ 22.3k) date utility library (see [docs](https://date-fns.org/docs/Getting-Started)).
9091
- [cross-env](https://github.com/kentcdodds/cross-env) (★ 4.9k) run scripts that set and use environment variables across platforms (see [docs](https://www.npmjs.com/package/cross-env)).
92+
- [Inquirer](https://github.com/SBoudrias/Inquirer.js/) (★ 12.2k) A collection of common interactive command line user interfaces (see [docs](https://github.com/SBoudrias/Inquirer.js/#documentation)).
9193

9294
### Unit Testing
9395

config.json

-1
This file was deleted.

firebase.json

+6-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@
2323
"predeploy": [
2424
"npm --prefix \"$RESOURCE_DIR\" run lint",
2525
"npm --prefix \"$RESOURCE_DIR\" run build"
26-
]
26+
],
27+
"source": "functions"
28+
},
29+
"firestore": {
30+
"rules": "firestore.rules",
31+
"indexes": "firestore.indexes.json"
2732
}
2833
}

firestore.indexes.json

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"indexes": [],
3+
"fieldOverrides": []
4+
}

firestore.rules

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
rules_version = '2';
2+
service cloud.firestore {
3+
match /databases/{database}/documents {
4+
5+
function isAuthenticated() {
6+
return request.auth != null && request.auth.token.email_verified == true;
7+
}
8+
9+
function isAdmin() {
10+
return request.auth.token.isAdmin == true;
11+
}
12+
13+
14+
match /users/{userId} {
15+
16+
function isUser() {
17+
return request.auth.uid == userId;
18+
}
19+
20+
allow read: if isAuthenticated() && (isAdmin() || isUser());
21+
22+
allow write: if isAuthenticated() && isAdmin();
23+
24+
allow update: if isAuthenticated() && (isAdmin() || isUser());
25+
26+
allow delete: if isAuthenticated() && isAdmin();
27+
}
28+
}
29+
}

functions/setupProject.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const admin = require('firebase-admin');
55
const inquirer = require('inquirer');
66
const fs = require('fs');
77

8-
const configPath = '../config.json';
8+
const configPath = '../src/state/api/index.js';
99

1010
const questions = [
1111
{
@@ -57,16 +57,16 @@ const deleteDatabase = async (database) => {
5757
fs.rmdirSync(`./src/${dir}`, { recursive: true });
5858

5959
console.log(`${database} cloud functions are deleted!`);
60-
} catch (err) {
61-
console.error(`Error while deleting ${database}.`);
60+
} catch (error) {
61+
console.error(`Error while deleting ${database}. ${error}`);
6262
}
6363

6464
try {
6565
fs.rmdirSync(`./test/${dir}`, { recursive: true });
6666

6767
console.log(`${dir} tests are deleted!`);
68-
} catch (err) {
69-
console.error(`Error while deleting ${database}.`);
68+
} catch (error) {
69+
console.error(`Error while deleting ${database} tests. ${error}`);
7070
}
7171
};
7272

src/state/api/firestore.js

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// eslint-disable-next-line no-unused-vars
2+
import { firestore } from 'firebase';
3+
4+
import firebase from 'firebase.js';
5+
6+
const getFirestoreRef = (path) => firebase.firestore().collection(path);
7+
8+
export const fetchDocument = async (collection, id) => {
9+
const document = await getFirestoreRef(collection).doc(id).get();
10+
if (!document.exists) {
11+
return null;
12+
}
13+
14+
return { id: document.id, ...document.data() };
15+
};
16+
17+
export const fetchCollection = async (collection, options = {}) => {
18+
const data = [];
19+
let baseQuery = getFirestoreRef(collection);
20+
21+
if (options.queries) {
22+
const { queries } = options;
23+
queries.forEach(({ attribute, operator, value }) => {
24+
baseQuery = baseQuery.where(attribute, operator, value);
25+
});
26+
}
27+
28+
if (options.sort) {
29+
const { attribute, order } = options.sort;
30+
baseQuery = baseQuery.orderBy(attribute, order);
31+
}
32+
(await baseQuery.get()).forEach((doc) =>
33+
data.push({ id: doc.id, ...doc.data() })
34+
);
35+
36+
return data;
37+
};
38+
39+
export const deleteDocument = (collection, id) => {
40+
return getFirestoreRef(collection).doc(id).delete();
41+
};
42+
43+
export const createDocument = (collection, id, values) => {
44+
return getFirestoreRef(collection).doc(id).set(values);
45+
};
46+
47+
export const modifyDocument = (collection, id, values) => {
48+
return getFirestoreRef(collection).doc(id).update(values);
49+
};

src/state/api/index.js

+14-42
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,15 @@
1-
import firebase from 'firebase.js';
2-
3-
const getRealTimeRef = (path) => firebase.database().ref(path);
4-
5-
export const fetchDocument = async (collection, id) => {
6-
const document = (
7-
await getRealTimeRef(`${collection}/${id}`).once(`value`)
8-
).val();
9-
10-
return document ? { id, ...document } : null;
11-
};
12-
13-
export const fetchCollection = async (collection, options = {}) => {
14-
let baseQuery = getRealTimeRef(collection);
15-
16-
if (options.filterBy) {
17-
const { filterBy, value } = options;
18-
baseQuery = baseQuery.orderByChild(filterBy).equalTo(value);
19-
}
20-
21-
const fetchedCollection = (await baseQuery.once('value')).val();
22-
23-
const data = fetchedCollection
24-
? Object.entries(fetchedCollection).map(([key, value]) => ({
25-
id: key,
26-
...value,
27-
}))
28-
: [];
29-
30-
return data;
31-
};
32-
33-
export const deleteDocument = (collection, id) => {
34-
return getRealTimeRef(`${collection}/${id}`).remove();
35-
};
36-
37-
export const createDocument = (collection, id, values) => {
38-
return getRealTimeRef(`${collection}/${id}`).set(values);
39-
};
40-
41-
export const modifyDocument = (collection, id, values) => {
42-
return getRealTimeRef(`${collection}/${id}`).update(values);
1+
import {
2+
createDocument,
3+
deleteDocument,
4+
fetchCollection,
5+
fetchDocument,
6+
modifyDocument,
7+
} from './rtdb';
8+
9+
export {
10+
createDocument,
11+
deleteDocument,
12+
fetchCollection,
13+
fetchDocument,
14+
modifyDocument,
4315
};

src/state/api/rtdb.js

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import firebase from 'firebase.js';
2+
3+
const getRealTimeRef = (path) => firebase.database().ref(path);
4+
5+
export const fetchDocument = async (collection, id) => {
6+
const document = (
7+
await getRealTimeRef(`${collection}/${id}`).once(`value`)
8+
).val();
9+
10+
return document ? { id, ...document } : null;
11+
};
12+
13+
export const fetchCollection = async (collection, options = {}) => {
14+
let baseQuery = getRealTimeRef(collection);
15+
16+
if (options.filterBy) {
17+
const { filterBy, value } = options;
18+
baseQuery = baseQuery.orderByChild(filterBy).equalTo(value);
19+
}
20+
21+
const fetchedCollection = (await baseQuery.once('value')).val();
22+
23+
const data = fetchedCollection
24+
? Object.entries(fetchedCollection).map(([key, value]) => ({
25+
id: key,
26+
...value,
27+
}))
28+
: [];
29+
30+
return data;
31+
};
32+
33+
export const deleteDocument = (collection, id) => {
34+
return getRealTimeRef(`${collection}/${id}`).remove();
35+
};
36+
37+
export const createDocument = (collection, id, values) => {
38+
return getRealTimeRef(`${collection}/${id}`).set(values);
39+
};
40+
41+
export const modifyDocument = (collection, id, values) => {
42+
return getRealTimeRef(`${collection}/${id}`).update(values);
43+
};

0 commit comments

Comments
 (0)