@rebasepro/client-firebase 0.6.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.umd.js CHANGED
@@ -1065,221 +1065,232 @@
1065
1065
  subscriptions.forEach((p) => p());
1066
1066
  };
1067
1067
  }, [firebaseApp, listenEntity]);
1068
- return {
1068
+ const initTextSearch = (0, react.useCallback)(async (props) => {
1069
+ console.debug("Init text search controller", searchControllerRef.current, props.path);
1070
+ if (!searchControllerRef.current) {
1071
+ console.warn("You are trying to use text search, but have not provided a text search controller in `useFirestoreDriver`. You can also set the flag `localTextSearchEnabled` to use local search in `useFirestoreDriver`. Local text search can incur in performance issues and higher costs for large datasets.");
1072
+ return false;
1073
+ }
1074
+ try {
1075
+ return searchControllerRef.current.init(props);
1076
+ } catch (e) {
1077
+ console.error("Error initializing text search controller", e);
1078
+ return false;
1079
+ }
1080
+ }, []);
1081
+ /**
1082
+ * Fetch entities in a Firestore path
1083
+ * @param path
1084
+ * @param collection
1085
+ * @param filter
1086
+ * @param limit
1087
+ * @param startAfter
1088
+ * @param searchString
1089
+ * @param orderBy
1090
+ * @param order
1091
+ * @return Function to cancel subscription
1092
+ * @see useCollectionFetch if you need this functionality implemented as a hook
1093
+ * @group Firestore
1094
+ */
1095
+ const fetchCollection = (0, react.useCallback)(async ({ path, filter, limit, startAfter, searchString, orderBy, order, collection }) => {
1096
+ const databaseId = collection?.databaseId;
1097
+ const resolvedPath = path;
1098
+ console.debug("Fetching collection", {
1099
+ path,
1100
+ limit,
1101
+ filter,
1102
+ startAfter,
1103
+ orderBy,
1104
+ order
1105
+ });
1106
+ return (await (0, _firebase_firestore.getDocs)(buildQuery(resolvedPath, filter, orderBy, order, startAfter, limit, databaseId))).docs.map((doc) => createEntityFromDocument(doc, databaseId));
1107
+ }, [buildQuery]);
1108
+ /**
1109
+ * Listen to a entities in a given path
1110
+ * @param path
1111
+ * @param collection
1112
+ * @param onError
1113
+ * @param filter
1114
+ * @param limit
1115
+ * @param startAfter
1116
+ * @param searchString
1117
+ * @param orderBy
1118
+ * @param order
1119
+ * @param onUpdate
1120
+ * @return Function to cancel subscription
1121
+ * @see useCollectionFetch if you need this functionality implemented as a hook
1122
+ * @group Firestore
1123
+ */
1124
+ const listenCollection = (0, react.useCallback)(({ path, filter, limit, startAfter, searchString, orderBy, order, onUpdate, onError, collection }) => {
1125
+ console.debug("Listening collection", {
1126
+ path,
1127
+ searchString,
1128
+ limit,
1129
+ filter,
1130
+ startAfter,
1131
+ orderBy,
1132
+ order,
1133
+ collection
1134
+ });
1135
+ if (!firebaseApp) throw Error("useFirestoreDriver Firebase not initialised");
1136
+ const databaseId = collection?.databaseId;
1137
+ if (searchString) return performTextSearch({
1138
+ path,
1139
+ searchString,
1140
+ onUpdate,
1141
+ databaseId
1142
+ });
1143
+ const resolvedPath = path;
1144
+ console.debug("Resolved path for listening", {
1145
+ path,
1146
+ resolvedPath
1147
+ });
1148
+ return (0, _firebase_firestore.onSnapshot)(buildQuery(resolvedPath, filter, orderBy, order, startAfter, limit, databaseId), {
1149
+ next: (snapshot) => {
1150
+ if (!searchString) onUpdate(snapshot.docs.map((doc) => createEntityFromDocument(doc, databaseId)));
1151
+ },
1152
+ error: onError
1153
+ });
1154
+ }, [
1155
+ buildQuery,
1156
+ firebaseApp,
1157
+ performTextSearch
1158
+ ]);
1159
+ /**
1160
+ * Retrieve an entity given a path and a collection
1161
+ * @param path
1162
+ * @param entityId
1163
+ * @param collection
1164
+ * @group Firestore
1165
+ */
1166
+ const fetchEntity = (0, react.useCallback)(({ path, entityId, collection }) => {
1167
+ return getAndBuildEntity(path, entityId, collection?.databaseId);
1168
+ }, [getAndBuildEntity]);
1169
+ /**
1170
+ * Save entity to the specified path. Note that Firestore does not allow
1171
+ * undefined values.
1172
+ * @param path
1173
+ * @param entityId
1174
+ * @param values
1175
+ * @param schemaId
1176
+ * @param collection
1177
+ * @param status
1178
+ * @group Firestore
1179
+ */
1180
+ const saveEntity = (0, react.useCallback)(({ path, entityId, values: valuesProp, collection, status }) => {
1181
+ if (!firebaseApp) throw Error("useFirestoreDriver Firebase not initialised");
1182
+ console.debug("1", {
1183
+ path,
1184
+ entityId,
1185
+ values: valuesProp,
1186
+ collection
1187
+ });
1188
+ const values = cmsToFirestoreModel(valuesProp, (0, _firebase_firestore.getFirestore)(firebaseApp));
1189
+ console.debug("2", {
1190
+ path,
1191
+ entityId,
1192
+ values: valuesProp,
1193
+ collection
1194
+ });
1195
+ const databaseId = collection?.databaseId;
1196
+ const collectionReference = (0, _firebase_firestore.collection)(databaseId ? (0, _firebase_firestore.getFirestore)(firebaseApp, databaseId) : (0, _firebase_firestore.getFirestore)(firebaseApp), path);
1197
+ console.debug("Saving entity", {
1198
+ path,
1199
+ entityId,
1200
+ values,
1201
+ databaseId
1202
+ });
1203
+ let documentReference;
1204
+ if (entityId) documentReference = (0, _firebase_firestore.doc)(collectionReference, String(entityId));
1205
+ else documentReference = (0, _firebase_firestore.doc)(collectionReference);
1206
+ return (0, _firebase_firestore.setDoc)(documentReference, values, { merge: true }).then(() => {
1207
+ return {
1208
+ id: documentReference.id,
1209
+ path,
1210
+ values: firestoreToCMSModel(values)
1211
+ };
1212
+ }).catch((error) => {
1213
+ console.error("Error saving entity", error);
1214
+ throw error;
1215
+ });
1216
+ }, [firebaseApp]);
1217
+ /**
1218
+ * Delete an entity
1219
+ * @param entity
1220
+ * @param collection
1221
+ * @group Firestore
1222
+ */
1223
+ const deleteEntity = (0, react.useCallback)(({ entity }) => {
1224
+ if (!firebaseApp) throw Error("useFirestoreDriver Firebase not initialised");
1225
+ const databaseId = entity.databaseId;
1226
+ return (0, _firebase_firestore.deleteDoc)((0, _firebase_firestore.doc)(databaseId ? (0, _firebase_firestore.getFirestore)(firebaseApp, databaseId) : (0, _firebase_firestore.getFirestore)(firebaseApp), entity.path, String(entity.id)));
1227
+ }, [firebaseApp]);
1228
+ /**
1229
+ * Check if the given property is unique in the given collection
1230
+ * @param path Collection path
1231
+ * @param name of the property
1232
+ * @param value
1233
+ * @param property
1234
+ * @param entityId
1235
+ * @return `true` if there are no other fields besides the given entity
1236
+ * @group Firestore
1237
+ */
1238
+ const checkUniqueField = (0, react.useCallback)(async (path, name, value, entityId, collection) => {
1239
+ if (!firebaseApp) throw Error("useFirestoreDriver Firebase not initialised");
1240
+ const databaseId = collection?.databaseId;
1241
+ const firestore = databaseId ? (0, _firebase_firestore.getFirestore)(firebaseApp, databaseId) : (0, _firebase_firestore.getFirestore)(firebaseApp);
1242
+ if (value === void 0 || value === null) return Promise.resolve(true);
1243
+ return (await (0, _firebase_firestore.getDocs)((0, _firebase_firestore.query)((0, _firebase_firestore.collection)(firestore, path), (0, _firebase_firestore.where)(name, "==", cmsToFirestoreModel(value, firestore))))).docs.filter((doc) => doc.id !== entityId).length === 0;
1244
+ }, [firebaseApp]);
1245
+ const countEntities = (0, react.useCallback)(async ({ path, filter, order, orderBy, collection }) => {
1246
+ if (!firebaseApp) throw Error("useFirestoreDriver Firebase not initialised");
1247
+ const databaseId = collection?.databaseId;
1248
+ return (await (0, _firebase_firestore.getCountFromServer)(buildQuery(path, filter, orderBy, order, void 0, void 0, databaseId))).data().count;
1249
+ }, [firebaseApp]);
1250
+ const isFilterCombinationValid = (0, react.useCallback)(({ path, collection, filterValues, sortBy }) => {
1251
+ if (!firebaseApp) throw Error("useFirestoreDriver Firebase not initialised");
1252
+ if (firestoreIndexesBuilder === void 0) return true;
1253
+ const indexes = firestoreIndexesBuilder?.({
1254
+ path,
1255
+ collection
1256
+ });
1257
+ const sortKey = sortBy ? sortBy[0] : void 0;
1258
+ const sortDirection = sortBy ? sortBy[1] : void 0;
1259
+ const values = Object.values(filterValues);
1260
+ const filterKeys = Object.keys(filterValues);
1261
+ const filtersCount = filterKeys.length;
1262
+ if (!sortKey && values.every((v) => v[0] === "==")) return true;
1263
+ if (filtersCount === 1 && (!sortKey || sortKey === filterKeys[0])) return true;
1264
+ if (!indexes && filtersCount > 1) return false;
1265
+ return !!indexes && indexes.filter((compositeIndex) => !sortKey || sortKey in compositeIndex).find((compositeIndex) => Object.entries(filterValues).every(([key, value]) => compositeIndex[key] !== void 0 && (!sortDirection || compositeIndex[key] === sortDirection))) !== void 0;
1266
+ }, [firebaseApp]);
1267
+ return (0, react.useMemo)(() => ({
1069
1268
  key: "firestore",
1070
1269
  currentTime,
1071
1270
  initialised: Boolean(firebaseApp),
1072
- initTextSearch: (0, react.useCallback)(async (props) => {
1073
- console.debug("Init text search controller", searchControllerRef.current, props.path);
1074
- if (!searchControllerRef.current) {
1075
- console.warn("You are trying to use text search, but have not provided a text search controller in `useFirestoreDriver`. You can also set the flag `localTextSearchEnabled` to use local search in `useFirestoreDriver`. Local text search can incur in performance issues and higher costs for large datasets.");
1076
- return false;
1077
- }
1078
- try {
1079
- return searchControllerRef.current.init(props);
1080
- } catch (e) {
1081
- console.error("Error initializing text search controller", e);
1082
- return false;
1083
- }
1084
- }, []),
1085
- /**
1086
- * Fetch entities in a Firestore path
1087
- * @param path
1088
- * @param collection
1089
- * @param filter
1090
- * @param limit
1091
- * @param startAfter
1092
- * @param searchString
1093
- * @param orderBy
1094
- * @param order
1095
- * @return Function to cancel subscription
1096
- * @see useCollectionFetch if you need this functionality implemented as a hook
1097
- * @group Firestore
1098
- */
1099
- fetchCollection: (0, react.useCallback)(async ({ path, filter, limit, startAfter, searchString, orderBy, order, collection }) => {
1100
- const databaseId = collection?.databaseId;
1101
- const resolvedPath = path;
1102
- console.debug("Fetching collection", {
1103
- path,
1104
- limit,
1105
- filter,
1106
- startAfter,
1107
- orderBy,
1108
- order
1109
- });
1110
- return (await (0, _firebase_firestore.getDocs)(buildQuery(resolvedPath, filter, orderBy, order, startAfter, limit, databaseId))).docs.map((doc) => createEntityFromDocument(doc, databaseId));
1111
- }, [buildQuery]),
1112
- /**
1113
- * Listen to a entities in a given path
1114
- * @param path
1115
- * @param collection
1116
- * @param onError
1117
- * @param filter
1118
- * @param limit
1119
- * @param startAfter
1120
- * @param searchString
1121
- * @param orderBy
1122
- * @param order
1123
- * @param onUpdate
1124
- * @return Function to cancel subscription
1125
- * @see useCollectionFetch if you need this functionality implemented as a hook
1126
- * @group Firestore
1127
- */
1128
- listenCollection: (0, react.useCallback)(({ path, filter, limit, startAfter, searchString, orderBy, order, onUpdate, onError, collection }) => {
1129
- console.debug("Listening collection", {
1130
- path,
1131
- searchString,
1132
- limit,
1133
- filter,
1134
- startAfter,
1135
- orderBy,
1136
- order,
1137
- collection
1138
- });
1139
- if (!firebaseApp) throw Error("useFirestoreDriver Firebase not initialised");
1140
- const databaseId = collection?.databaseId;
1141
- if (searchString) return performTextSearch({
1142
- path,
1143
- searchString,
1144
- onUpdate,
1145
- databaseId
1146
- });
1147
- const resolvedPath = path;
1148
- console.debug("Resolved path for listening", {
1149
- path,
1150
- resolvedPath
1151
- });
1152
- return (0, _firebase_firestore.onSnapshot)(buildQuery(resolvedPath, filter, orderBy, order, startAfter, limit, databaseId), {
1153
- next: (snapshot) => {
1154
- if (!searchString) onUpdate(snapshot.docs.map((doc) => createEntityFromDocument(doc, databaseId)));
1155
- },
1156
- error: onError
1157
- });
1158
- }, [
1159
- buildQuery,
1160
- firebaseApp,
1161
- performTextSearch
1162
- ]),
1163
- /**
1164
- * Retrieve an entity given a path and a collection
1165
- * @param path
1166
- * @param entityId
1167
- * @param collection
1168
- * @group Firestore
1169
- */
1170
- fetchEntity: (0, react.useCallback)(({ path, entityId, collection }) => {
1171
- return getAndBuildEntity(path, entityId, collection?.databaseId);
1172
- }, [getAndBuildEntity]),
1173
- /**
1174
- *
1175
- * @param path
1176
- * @param entityId
1177
- * @param collection
1178
- * @param onUpdate
1179
- * @param onError
1180
- * @return Function to cancel subscription
1181
- * @group Firestore
1182
- */
1271
+ initTextSearch,
1272
+ fetchCollection,
1273
+ listenCollection,
1274
+ fetchEntity,
1183
1275
  listenEntity,
1184
- /**
1185
- * Save entity to the specified path. Note that Firestore does not allow
1186
- * undefined values.
1187
- * @param path
1188
- * @param entityId
1189
- * @param values
1190
- * @param schemaId
1191
- * @param collection
1192
- * @param status
1193
- * @group Firestore
1194
- */
1195
- saveEntity: (0, react.useCallback)(({ path, entityId, values: valuesProp, collection, status }) => {
1196
- if (!firebaseApp) throw Error("useFirestoreDriver Firebase not initialised");
1197
- console.debug("1", {
1198
- path,
1199
- entityId,
1200
- values: valuesProp,
1201
- collection
1202
- });
1203
- const values = cmsToFirestoreModel(valuesProp, (0, _firebase_firestore.getFirestore)(firebaseApp));
1204
- console.debug("2", {
1205
- path,
1206
- entityId,
1207
- values: valuesProp,
1208
- collection
1209
- });
1210
- const databaseId = collection?.databaseId;
1211
- const collectionReference = (0, _firebase_firestore.collection)(databaseId ? (0, _firebase_firestore.getFirestore)(firebaseApp, databaseId) : (0, _firebase_firestore.getFirestore)(firebaseApp), path);
1212
- console.debug("Saving entity", {
1213
- path,
1214
- entityId,
1215
- values,
1216
- databaseId
1217
- });
1218
- let documentReference;
1219
- if (entityId) documentReference = (0, _firebase_firestore.doc)(collectionReference, String(entityId));
1220
- else documentReference = (0, _firebase_firestore.doc)(collectionReference);
1221
- return (0, _firebase_firestore.setDoc)(documentReference, values, { merge: true }).then(() => {
1222
- return {
1223
- id: documentReference.id,
1224
- path,
1225
- values: firestoreToCMSModel(values)
1226
- };
1227
- }).catch((error) => {
1228
- console.error("Error saving entity", error);
1229
- throw error;
1230
- });
1231
- }, [firebaseApp]),
1232
- /**
1233
- * Delete an entity
1234
- * @param entity
1235
- * @param collection
1236
- * @group Firestore
1237
- */
1238
- deleteEntity: (0, react.useCallback)(({ entity }) => {
1239
- if (!firebaseApp) throw Error("useFirestoreDriver Firebase not initialised");
1240
- const databaseId = entity.databaseId;
1241
- return (0, _firebase_firestore.deleteDoc)((0, _firebase_firestore.doc)(databaseId ? (0, _firebase_firestore.getFirestore)(firebaseApp, databaseId) : (0, _firebase_firestore.getFirestore)(firebaseApp), entity.path, String(entity.id)));
1242
- }, [firebaseApp]),
1243
- /**
1244
- * Check if the given property is unique in the given collection
1245
- * @param path Collection path
1246
- * @param name of the property
1247
- * @param value
1248
- * @param property
1249
- * @param entityId
1250
- * @return `true` if there are no other fields besides the given entity
1251
- * @group Firestore
1252
- */
1253
- checkUniqueField: (0, react.useCallback)(async (path, name, value, entityId, collection) => {
1254
- if (!firebaseApp) throw Error("useFirestoreDriver Firebase not initialised");
1255
- const databaseId = collection?.databaseId;
1256
- const firestore = databaseId ? (0, _firebase_firestore.getFirestore)(firebaseApp, databaseId) : (0, _firebase_firestore.getFirestore)(firebaseApp);
1257
- if (value === void 0 || value === null) return Promise.resolve(true);
1258
- return (await (0, _firebase_firestore.getDocs)((0, _firebase_firestore.query)((0, _firebase_firestore.collection)(firestore, path), (0, _firebase_firestore.where)(name, "==", cmsToFirestoreModel(value, firestore))))).docs.filter((doc) => doc.id !== entityId).length === 0;
1259
- }, [firebaseApp]),
1260
- countEntities: (0, react.useCallback)(async ({ path, filter, order, orderBy, collection }) => {
1261
- if (!firebaseApp) throw Error("useFirestoreDriver Firebase not initialised");
1262
- const databaseId = collection?.databaseId;
1263
- return (await (0, _firebase_firestore.getCountFromServer)(buildQuery(path, filter, orderBy, order, void 0, void 0, databaseId))).data().count;
1264
- }, [firebaseApp]),
1265
- isFilterCombinationValid: (0, react.useCallback)(({ path, collection, filterValues, sortBy }) => {
1266
- if (!firebaseApp) throw Error("useFirestoreDriver Firebase not initialised");
1267
- if (firestoreIndexesBuilder === void 0) return true;
1268
- const indexes = firestoreIndexesBuilder?.({
1269
- path,
1270
- collection
1271
- });
1272
- const sortKey = sortBy ? sortBy[0] : void 0;
1273
- const sortDirection = sortBy ? sortBy[1] : void 0;
1274
- const values = Object.values(filterValues);
1275
- const filterKeys = Object.keys(filterValues);
1276
- const filtersCount = filterKeys.length;
1277
- if (!sortKey && values.every((v) => v[0] === "==")) return true;
1278
- if (filtersCount === 1 && (!sortKey || sortKey === filterKeys[0])) return true;
1279
- if (!indexes && filtersCount > 1) return false;
1280
- return !!indexes && indexes.filter((compositeIndex) => !sortKey || sortKey in compositeIndex).find((compositeIndex) => Object.entries(filterValues).every(([key, value]) => compositeIndex[key] !== void 0 && (!sortDirection || compositeIndex[key] === sortDirection))) !== void 0;
1281
- }, [firebaseApp])
1282
- };
1276
+ saveEntity,
1277
+ deleteEntity,
1278
+ checkUniqueField,
1279
+ countEntities,
1280
+ isFilterCombinationValid
1281
+ }), [
1282
+ firebaseApp,
1283
+ initTextSearch,
1284
+ fetchCollection,
1285
+ listenCollection,
1286
+ fetchEntity,
1287
+ listenEntity,
1288
+ saveEntity,
1289
+ deleteEntity,
1290
+ checkUniqueField,
1291
+ countEntities,
1292
+ isFilterCombinationValid
1293
+ ]);
1283
1294
  }
1284
1295
  var createEntityFromDocument = (docSnap, databaseId) => {
1285
1296
  const values = firestoreToCMSModel(docSnap.data());