unfire
Version:
⚡️ Utilities for Firebase 🔥 built with Composition API, Typescript and ❤️
357 lines (352 loc) • 13 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/vue/index.ts
var vue_exports = {};
__export(vue_exports, {
createPathRef: () => createPathRef,
deleteDoc: () => deleteDoc,
toReactiveQueryOption: () => toReactiveQueryOption,
upsertDoc: () => upsertDoc,
useCollection: () => useCollection,
useDoc: () => useDoc,
useDocBiDirection: () => useDocBiDirection,
whereFilterOps: () => whereFilterOps
});
module.exports = __toCommonJS(vue_exports);
// src/vue/vue-composables.ts
var import_vue = require("vue");
var import_core = require("@vueuse/core");
// src/firebase/firestore.ts
var import_unfire_init = require("@unfire-init");
var import_unfire_firestore_schema = require("@unfire-firestore-schema");
var import_unfire_init2 = require("@unfire-init");
var defaultWhereQueryBuilder = (...query2) => query2;
var queryBuilder = ({
whereQueries,
orderByQuery,
limitBy
}) => {
return [
...whereQueries ? whereQueries({ where: defaultWhereQueryBuilder }).map((query2) => (0, import_unfire_init.where)(...query2)) : [],
...orderByQuery ? [(0, import_unfire_init.orderBy)(orderByQuery.fieldPath, orderByQuery.directionStr)] : [],
...limitBy ? [(0, import_unfire_init.limit)(limitBy)] : []
];
};
var getDocData = (docRef) => {
const data = docRef.data();
if (data) {
Object.defineProperty(data, "id", {
value: docRef.id.toString(),
writable: false
});
}
return data;
};
var createCollection = (collectionPath, firestoreInstance) => {
console.log("in createCollection");
return (0, import_unfire_init.collection)(firestoreInstance != null ? firestoreInstance : (0, import_unfire_init.getFirestore)(), collectionPath);
};
var getCollectionDocRef = (collectionPath, docId, firestoreInstance) => (0, import_unfire_init.doc)(createCollection(collectionPath, firestoreInstance), docId);
var upsertDoc = async (options) => {
var _a;
const {
data,
collectionPath,
docId,
docRef,
setOption,
validation = true,
customSchema,
onSuccess,
onError
} = options;
const ref2 = docRef != null ? docRef : docId ? getCollectionDocRef(collectionPath, docId) : (0, import_unfire_init.doc)(createCollection(collectionPath));
try {
if (validation) {
const schema = customSchema != null ? customSchema : await (0, import_unfire_firestore_schema.ImportFirestoreSchemaByPath)(collectionPath);
const schemaParseResult = schema == null ? void 0 : schema.safeParse(data);
(schemaParseResult == null ? void 0 : schemaParseResult.success) ? await (0, import_unfire_init.setDoc)(ref2, schemaParseResult.data, setOption != null ? setOption : { merge: true }).then(() => {
onSuccess == null ? void 0 : onSuccess(schemaParseResult.data);
}) : onError == null ? void 0 : onError((_a = schemaParseResult == null ? void 0 : schemaParseResult.error) != null ? _a : new Error("No Schema Found"));
} else {
await (0, import_unfire_init.setDoc)(ref2, data, setOption != null ? setOption : { merge: true }).then(() => {
onSuccess == null ? void 0 : onSuccess(data);
});
}
} catch (error) {
onError == null ? void 0 : onError(error);
}
return ref2;
};
var queryCollection = (options) => {
const {
collectionPath,
onSnapshot,
onError,
queryOption,
snapshotListenOptions = { includeMetadataChanges: false }
} = options;
try {
const q = (0, import_unfire_init.query)(createCollection(collectionPath), ...queryOption ? queryBuilder(queryOption) : []);
return {
unsubscribe: (0, import_unfire_init.onSnapshot)(q, snapshotListenOptions, {
next: (snapshot) => {
onSnapshot({ snapshot, docsData: snapshot.docs.map(getDocData) });
},
error: onError
})
};
} catch (error) {
onError == null ? void 0 : onError(error);
return { error };
}
};
var queryDoc = (options) => {
const {
collectionPath,
docId,
docRef,
onSnapshot,
onError,
snapshotListenOptions = { includeMetadataChanges: false }
} = options;
try {
if (docRef) {
return {
unsubscribe: (0, import_unfire_init.onSnapshot)(docRef, snapshotListenOptions, {
next: (snapshot) => {
onSnapshot({ snapshot, docData: getDocData(snapshot) });
},
error: onError
})
};
} else if (collectionPath && docId) {
return {
unsubscribe: (0, import_unfire_init.onSnapshot)(getCollectionDocRef(collectionPath, docId), snapshotListenOptions, {
next: (snapshot) => {
onSnapshot({ snapshot, docData: getDocData(snapshot) });
},
error: onError
})
};
} else {
const error = new Error('must provide "collectionPath" and "docId" or "docRef"');
onError == null ? void 0 : onError(error);
return { error };
}
} catch (error) {
onError == null ? void 0 : onError(error);
return { error };
}
};
var deleteDoc = (options) => {
const { collectionPath, docId, docRef, onError } = options;
try {
if (docRef) {
return (0, import_unfire_init.deleteDoc)(docRef);
} else if (collectionPath && docId) {
return (0, import_unfire_init.deleteDoc)(getCollectionDocRef(collectionPath, docId));
} else {
throw new Error('must provide "collectionPath" and "docId" or "docRef"');
}
} catch (error) {
onError == null ? void 0 : onError(error);
}
};
var whereFilterOps = ["==", "!=", ">", ">=", "<", "<=", "array-contains", "array-contains-any", "in", "not-in"];
// src/vue/vue-composables.ts
var createPathRef = (path) => (0, import_vue.ref)(path);
var toReactiveQueryOption = (queryOption) => (0, import_vue.reactive)(queryOption);
var useCollection = (options) => {
var _a;
const {
collectionPath: _collectionPath,
resultsRef,
queryOption,
onError,
snapshotListenOptions,
optionsWatchDebounce = 20
} = options;
console.log({ resultsRef });
const results = resultsRef != null ? resultsRef : (0, import_vue.ref)([]);
const unsubscribe = (0, import_vue.ref)();
const collectionPath = (0, import_vue.ref)(_collectionPath);
const _queryOption = (0, import_vue.ref)();
const initialWhereQueries = (_a = queryOption == null ? void 0 : queryOption.whereQueries) == null ? void 0 : _a.call(queryOption, { where: defaultWhereQueryBuilder }).map(([fieldPath, opStr, value]) => ({ fieldPath, opStr, value }));
const whereQueries = (0, import_vue.ref)(initialWhereQueries != null ? initialWhereQueries : []);
const orderByQuery = (0, import_vue.ref)(queryOption == null ? void 0 : queryOption.orderByQuery);
const limitBy = (0, import_vue.ref)(queryOption == null ? void 0 : queryOption.limitBy);
const stopQueryOptionWatch = (0, import_vue.watch)([whereQueries, orderByQuery, limitBy], ([queries, orderBy2, limit2]) => {
_queryOption.value = {
whereQueries: ({ where: where2 }) => queries.map(({ fieldPath, opStr, value }) => where2(fieldPath, opStr, value)),
limitBy: limit2,
orderByQuery: orderBy2
};
}, { immediate: true, deep: true });
const debounce = (0, import_vue.computed)(() => unsubscribe.value ? (0, import_vue.ref)(optionsWatchDebounce).value : 0);
const watchStopHandle = (0, import_core.debouncedWatch)([collectionPath, _queryOption], ([collectionPath2, queryOption2]) => {
var _a2;
(_a2 = unsubscribe.value) == null ? void 0 : _a2.call(unsubscribe);
unsubscribe.value = queryCollection({
collectionPath: collectionPath2,
queryOption: queryOption2,
onSnapshot: ({ docsData }) => {
results.value = docsData;
},
onError,
snapshotListenOptions
}).unsubscribe;
}, { immediate: true, debounce, deep: true });
const stop = () => {
var _a2;
(_a2 = unsubscribe.value) == null ? void 0 : _a2.call(unsubscribe);
watchStopHandle();
stopQueryOptionWatch();
};
(0, import_vue.onUnmounted)(() => {
stop();
});
return { results, stop, whereQueries, orderByQuery, limitBy };
};
var useDoc = (options) => {
const {
collectionPath: _collectionPath,
docId: _docId,
onError,
snapshotListenOptions,
optionsWatchDebounce = 20
} = options;
const result = (0, import_vue.ref)();
const unsubscribe = (0, import_vue.ref)();
const collectionPath = (0, import_vue.ref)(_collectionPath);
const docId = (0, import_vue.ref)(_docId);
const debounce = (0, import_vue.computed)(() => unsubscribe.value ? (0, import_vue.ref)(optionsWatchDebounce).value : 0);
const watchStopHandle = (0, import_core.debouncedWatch)([collectionPath, docId], ([collectionPath2, docId2]) => {
var _a;
(_a = unsubscribe.value) == null ? void 0 : _a.call(unsubscribe);
unsubscribe.value = queryDoc({
collectionPath: collectionPath2,
docId: docId2,
onSnapshot: ({ docData }) => {
result.value = docData;
},
onError,
snapshotListenOptions
}).unsubscribe;
}, { immediate: true, debounce });
const stop = () => {
var _a;
watchStopHandle();
(_a = unsubscribe.value) == null ? void 0 : _a.call(unsubscribe);
};
(0, import_vue.onUnmounted)(() => {
stop();
});
return { result, stop };
};
var useDocBiDirection = (options) => {
const {
collectionPath: _collectionPath,
docId: _docId,
onError,
onUpdateSuccess,
snapshotListenOptions,
refWatchUpdateDebounce = 200,
optionsWatchDebounce = 20,
updateValidation,
updateCustomSchema
} = options;
const result = (0, import_vue.ref)();
const validationError = (0, import_vue.ref)();
const unsubscribe = (0, import_vue.ref)();
const collectionPath = (0, import_vue.ref)(_collectionPath);
const docId = (0, import_vue.ref)(_docId);
const resetValidationError = () => {
validationError.value = void 0;
};
const updateDoc = (data) => {
return upsertDoc({
collectionPath: collectionPath.value,
docId: docId.value,
data,
validation: (0, import_vue.isRef)(updateValidation) ? updateValidation.value : updateValidation,
customSchema: updateCustomSchema,
onSuccess: (data2) => {
resetValidationError();
onUpdateSuccess == null ? void 0 : onUpdateSuccess(data2);
},
onError: (e) => {
onError == null ? void 0 : onError(e);
if ("issues" in e)
validationError.value = e;
}
});
};
const debounce = (0, import_vue.computed)(() => unsubscribe.value ? (0, import_vue.ref)(optionsWatchDebounce).value : 0);
let shouldUpdateDoc = false;
let localUpdated = false;
const resultWatchStopHandle = (0, import_core.debouncedWatch)(result, async (newResult) => {
if (newResult && shouldUpdateDoc) {
localUpdated = true;
await updateDoc(newResult);
localUpdated = false;
}
}, { deep: true, debounce: refWatchUpdateDebounce });
const shouldUpdateDelay = (0, import_vue.computed)(() => (0, import_vue.ref)(refWatchUpdateDebounce).value + 100);
const setShouldUpdateDoc = (0, import_core.useDebounceFn)(() => {
shouldUpdateDoc = true;
}, shouldUpdateDelay);
const optionsWatchStopHandle = (0, import_core.debouncedWatch)([collectionPath, docId], ([collectionPath2, docId2]) => {
var _a;
(_a = unsubscribe.value) == null ? void 0 : _a.call(unsubscribe);
unsubscribe.value = queryDoc({
collectionPath: collectionPath2,
docId: docId2,
onSnapshot: ({ docData }) => {
if (!localUpdated) {
shouldUpdateDoc = false;
result.value = docData;
setShouldUpdateDoc();
}
},
onError,
snapshotListenOptions
}).unsubscribe;
}, { immediate: true, debounce });
const stop = () => {
var _a;
resultWatchStopHandle();
optionsWatchStopHandle();
(_a = unsubscribe.value) == null ? void 0 : _a.call(unsubscribe);
};
(0, import_vue.onUnmounted)(() => {
stop();
});
return { result, validationError, updateDoc, resetValidationError, stop };
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
createPathRef,
deleteDoc,
toReactiveQueryOption,
upsertDoc,
useCollection,
useDoc,
useDocBiDirection,
whereFilterOps
});