mockbase
Version:
Firebase v7+ mock.
255 lines • 10.6 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MockQuery = exports.QUERY_SNAPSHOT_COMPLETE_EVENT = exports.QUERY_SNAPSHOT_ERROR_EVENT = exports.QUERY_SNAPSHOT_NEXT_EVENT = void 0;
const firebase = require("firebase");
const util_1 = require("../util");
const document_snapshot_1 = require("./document-snapshot");
const query_snapshot_1 = require("./query-snapshot");
exports.QUERY_SNAPSHOT_NEXT_EVENT = "snapshot:next";
exports.QUERY_SNAPSHOT_ERROR_EVENT = "snapshot:error";
exports.QUERY_SNAPSHOT_COMPLETE_EVENT = "snapshot:complete";
class MockQuery {
constructor(firestore, path, converter) {
this.firestore = firestore;
this.path = path;
this.converter = converter;
this.filters = {};
this.noInitialSnapshot = false;
}
get emitter() {
const emitter = this.firestore.collectionEvents.get(this.path) || new util_1.EventEmitter();
this.firestore.collectionEvents.set(this.path, emitter);
return emitter;
}
emitChange() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.emitter.hasListeners(exports.QUERY_SNAPSHOT_NEXT_EVENT)) {
return;
}
// TODO: this emits even if there wasn't an actual change with the current filters
const snapshot = yield this.get();
this.emitter.emit(exports.QUERY_SNAPSHOT_NEXT_EVENT, [snapshot]);
});
}
setNoInitialSnapshot() {
this.noInitialSnapshot = true;
return this;
}
clone() {
const query = new MockQuery(this.firestore, this.path, this.converter);
Object.assign(query, this);
query.filters = Object.assign({}, this.filters);
return query;
}
where(fieldPath, opStr, value) {
const key = `where:${fieldPath}:${opStr}:${value}`;
const query = this.clone();
query.filters[key] = (doc) => {
const fieldValue = doc.get(fieldPath.toString());
switch (opStr) {
case "==":
return fieldValue == value;
case ">":
return fieldValue > value;
case "<":
return fieldValue < value;
case ">=":
return fieldValue >= value;
case "<=":
return fieldValue <= value;
default:
return true;
}
};
return query;
}
orderBy(fieldPath, direction = "asc") {
if (fieldPath instanceof firebase.firestore.FieldPath) {
throw new Error("Ordering a query by FieldPath is not supported");
}
const query = this.clone();
query.ordering = { fieldPath, direction };
return query;
}
limit(limit) {
const query = this.clone();
query.docsStartLimit = limit;
query.docsEndLimit = undefined;
return query;
}
limitToLast(limit) {
const query = this.clone();
query.docsStartLimit = undefined;
query.docsEndLimit = limit;
return query;
}
startAt(value, ...rest) {
const query = this.clone();
query.addStartFilter({ value, inclusive: true });
return query;
}
startAfter(value, ...rest) {
const query = this.clone();
query.addStartFilter({ value, inclusive: false });
return query;
}
addStartFilter({ value, inclusive }) {
const findStartingIndex = value instanceof document_snapshot_1.MockDocumentSnapshot
? (docs) => docs.findIndex((doc) => {
return value.isEqual(doc);
}) + (inclusive ? 0 : 1)
: (docs, ordering) => docs.findIndex((doc) => {
const fieldValue = doc.get(ordering.fieldPath);
return inclusive ? fieldValue >= value : fieldValue > value;
});
this.filters["start"] = (_doc, index, allDocs) => {
const { ordering } = this;
if (!ordering) {
return true;
}
const startingIndex = findStartingIndex(allDocs, ordering);
return startingIndex <= index;
};
}
endBefore(value, ...rest) {
const query = this.clone();
query.addEndFilter({ value, inclusive: false });
return query;
}
endAt(value, ...rest) {
const query = this.clone();
query.addEndFilter({ value, inclusive: true });
return query;
}
addEndFilter({ value, inclusive }) {
const findEndingIndex = value instanceof document_snapshot_1.MockDocumentSnapshot
? (docs) => docs.findIndex((doc) => {
return value.isEqual(doc);
}) + (inclusive ? 1 : 0)
: (docs, ordering) => docs.length -
docs
.slice()
.reverse()
.findIndex((doc) => {
const fieldValue = doc.get(ordering.fieldPath);
return inclusive ? fieldValue <= value : fieldValue < value;
});
this.filters["end"] = (_doc, index, allDocs) => {
const { ordering } = this;
if (!ordering) {
return true;
}
const endingIndex = findEndingIndex(allDocs, ordering);
return endingIndex > index;
};
}
isEqual(other) {
var _a, _b, _c, _d;
if (other.firestore !== this.firestore ||
!(other instanceof MockQuery) ||
other.path !== this.path ||
other.converter !== this.converter) {
return false;
}
const filtersMatch = Object.keys(other.filters).join(",") === Object.keys(this.filters).join(",");
const limitsMatch = other.docsStartLimit === this.docsStartLimit && other.docsEndLimit === this.docsEndLimit;
if (!filtersMatch || !limitsMatch) {
return false;
}
if ((!other.ordering && this.ordering) || (other.ordering && !this.ordering)) {
return false;
}
const orderingMatches = ((_a = other.ordering) === null || _a === void 0 ? void 0 : _a.direction) === ((_b = this.ordering) === null || _b === void 0 ? void 0 : _b.direction) &&
((_c = other.ordering) === null || _c === void 0 ? void 0 : _c.fieldPath) === ((_d = this.ordering) === null || _d === void 0 ? void 0 : _d.fieldPath);
if (!orderingMatches) {
return false;
}
return true;
}
compareFunction(a, b) {
if (!this.ordering) {
return 0;
}
const direction = this.ordering.direction === "asc" ? 1 : -1;
const aValue = a.get(this.ordering.fieldPath);
const bValue = b.get(this.ordering.fieldPath);
if (aValue == null || bValue == null) {
return aValue === bValue ? 0 : (aValue == null ? -1 : 1) * direction;
}
const result = aValue === bValue ? 0 : aValue < bValue ? -1 : 1;
return result * direction;
}
/**
* Gets a list of doc keys that should be fetched by the #get() method.
* Made protected so that the collection group implementation can override it.
*/
getCandidateDocKeys() {
return this.firestore.collectionDocuments.get(this.path) || new Set();
}
get(options) {
if (!this.ordering && this.docsEndLimit) {
return Promise.reject(new Error("#orderBy() not specified with #limitToLast()"));
}
const allDocs = Array.from(this.getCandidateDocKeys().values());
const allSnapshots = allDocs.map((doc) => new document_snapshot_1.MockQueryDocumentSnapshot(this.firestore.doc(doc).withConverter(this.converter), this.firestore.documentData.get(doc)));
const actualSnapshots = allSnapshots
.sort(this.compareFunction.bind(this))
.filter((snapshot, index) => Object.values(this.filters).every((filter) => filter(snapshot, index, allSnapshots)))
.slice(this.docsEndLimit ? -this.docsEndLimit : 0, this.docsStartLimit);
return Promise.resolve(new query_snapshot_1.MockQuerySnapshot(this, actualSnapshots));
}
onSnapshot(options, onNext, onError, onCompletion) {
let actualListeners;
if (typeof options === "object") {
if (typeof onNext === "object") {
actualListeners = onNext;
}
else if (typeof onNext === "function") {
actualListeners = {
next: onNext,
error: onError,
};
}
else {
actualListeners = options;
}
}
else {
actualListeners = {
next: options,
error: onNext,
};
}
let prevSnapshot;
const actualNext = (snapshot) => {
const surrogate = new query_snapshot_1.MockQuerySnapshot(this, snapshot.docs, prevSnapshot);
actualListeners.next(surrogate);
prevSnapshot = surrogate;
};
this.emitter.on(exports.QUERY_SNAPSHOT_NEXT_EVENT, actualNext);
actualListeners.error && this.emitter.on(exports.QUERY_SNAPSHOT_ERROR_EVENT, actualListeners.error);
if (!this.noInitialSnapshot) {
this.get().then((snapshot) => actualNext(snapshot));
}
return () => {
this.emitter.off(exports.QUERY_SNAPSHOT_NEXT_EVENT, actualNext);
actualListeners.error && this.emitter.off(exports.QUERY_SNAPSHOT_ERROR_EVENT, actualListeners.error);
};
}
withConverter(converter) {
const query = this.clone();
query.converter = converter;
return query;
}
}
exports.MockQuery = MockQuery;
//# sourceMappingURL=query.js.map