@firestore-emulator/server
Version:
This package is the implementation of the Firestore emulator. It is a Node.js
395 lines (388 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/server/FirestoreServiceV1Impl/index.ts
var FirestoreServiceV1Impl_exports = {};
__export(FirestoreServiceV1Impl_exports, {
FirestoreServiceV1Impl: () => FirestoreServiceV1Impl
});
module.exports = __toCommonJS(FirestoreServiceV1Impl_exports);
var import_firestore2 = require("@firestore-emulator/proto/dist/google/firestore/v1/firestore");
var import_empty = require("@firestore-emulator/proto/dist/google/protobuf/empty");
// src/error/error.ts
var FirestoreEmulatorError = class extends Error {
constructor(code, message) {
super(message);
this.code = code;
}
};
// src/FirestoreState/index.ts
var import_node_events = require("events");
var import_document = require("@firestore-emulator/proto/dist/google/firestore/v1/document");
var import_firestore = require("@firestore-emulator/proto/dist/google/firestore/v1/firestore");
var import_query = require("@firestore-emulator/proto/dist/google/firestore/v1/query");
var import_write = require("@firestore-emulator/proto/dist/google/firestore/v1/write");
var import_timestamp = require("@firestore-emulator/proto/dist/google/protobuf/timestamp");
var import_constants = require("@grpc/grpc-js/build/src/constants");
var import_assert_never = require("assert-never");
var import_immer2 = require("immer");
// src/FirestoreState/field.ts
var import_struct = require("@firestore-emulator/proto/dist/google/protobuf/struct");
var FirestoreStateDocumentNullField = class {
type = "null_value";
value = null;
toJSON() {
return { type: this.type, value: null };
}
toV1ValueObject() {
return { null_value: import_struct.NullValue.NULL_VALUE };
}
eq(other) {
return other.type === this.type;
}
lt(_other) {
return false;
}
lte(_other) {
return false;
}
gt(_other) {
return false;
}
gte(_other) {
return false;
}
};
var FirestoreStateDocumentIntegerField = class _FirestoreStateDocumentIntegerField {
constructor(value) {
this.value = value;
if (!Number.isInteger(value)) {
throw new Error(`value must be integer. value=${value}`);
}
}
type = "integer_value";
toJSON() {
return { type: this.type, value: this.value };
}
toV1ValueObject() {
return { integer_value: this.value };
}
eq(other) {
return other instanceof _FirestoreStateDocumentIntegerField && this.value === other.value;
}
lt(other) {
return other instanceof _FirestoreStateDocumentIntegerField && this.value < other.value;
}
lte(other) {
return other instanceof _FirestoreStateDocumentIntegerField && this.value <= other.value;
}
gt(other) {
return other instanceof _FirestoreStateDocumentIntegerField && this.value > other.value;
}
gte(other) {
return other instanceof _FirestoreStateDocumentIntegerField && this.value >= other.value;
}
add(other) {
if (other instanceof _FirestoreStateDocumentIntegerField) {
return new _FirestoreStateDocumentIntegerField(this.value + other.value);
}
if (other instanceof FirestoreStateDocumentDoubleField) {
return new FirestoreStateDocumentDoubleField(this.value + other.value);
}
throw new Error(`unsupported type. other=${other}`);
}
};
var FirestoreStateDocumentDoubleField = class _FirestoreStateDocumentDoubleField {
constructor(value) {
this.value = value;
}
type = "double_value";
toJSON() {
return { type: this.type, value: this.value };
}
toV1ValueObject() {
return { double_value: this.value };
}
eq(other) {
return other instanceof _FirestoreStateDocumentDoubleField && this.value === other.value;
}
lt(other) {
return other instanceof _FirestoreStateDocumentDoubleField && this.value < other.value;
}
lte(other) {
return other instanceof _FirestoreStateDocumentDoubleField && this.value <= other.value;
}
gt(other) {
return other instanceof _FirestoreStateDocumentDoubleField && this.value > other.value;
}
gte(other) {
return other instanceof _FirestoreStateDocumentDoubleField && this.value >= other.value;
}
add(other) {
if (other instanceof FirestoreStateDocumentIntegerField) {
return new _FirestoreStateDocumentDoubleField(this.value + other.value);
}
if (other instanceof _FirestoreStateDocumentDoubleField) {
return new _FirestoreStateDocumentDoubleField(this.value + other.value);
}
throw new Error(`unsupported type. other=${other}`);
}
};
// src/FirestoreState/mask.ts
var import_immer = require("immer");
// src/FirestoreState/index.ts
var TimestampFromDate = (date) => import_timestamp.Timestamp.fromObject({
nanos: date.getTime() % 1e3 * 1e3 * 1e3,
seconds: Math.floor(date.getTime() / 1e3)
});
var TimestampFromNow = () => TimestampFromDate(/* @__PURE__ */ new Date());
// src/server/FirestoreServiceV1Impl/index.ts
var FirestoreServiceV1Impl = class extends import_firestore2.UnimplementedFirestoreService {
#state;
constructor(state) {
super();
this.#state = state;
}
GetDocument(_call, _callback) {
console.error("Method<GetDocument> not implemented.");
throw new Error("Method<GetDocument> not implemented.");
}
ListDocuments(_call, _callback) {
console.error("Method<ListDocuments> not implemented.");
throw new Error("Method<ListDocuments> not implemented.");
}
UpdateDocument(_call, _callback) {
console.error("Method<UpdateDocument> not implemented.");
throw new Error("Method<UpdateDocument> not implemented.");
}
DeleteDocument(_call, _callback) {
console.error("Method<DeleteDocument> not implemented.");
throw new Error("Method<DeleteDocument> not implemented.");
}
BatchGetDocuments(call) {
const date = TimestampFromNow();
const tx = call.request.has_new_transaction ? Uint8Array.from([17, 2, 0, 0, 0, 0, 0, 0, 0]) : null;
if (tx) {
call.write(
import_firestore2.BatchGetDocumentsResponse.fromObject({
transaction: tx
})
);
}
for (const documentPath of call.request.documents) {
const document = this.#state.getDocument(documentPath);
call.write(
import_firestore2.BatchGetDocumentsResponse.fromObject({
found: document.metadata.hasExist ? document.toV1DocumentObject() : void 0,
missing: document.metadata.hasExist ? void 0 : documentPath,
read_time: date
})
);
}
call.end();
}
BeginTransaction(_call, callback) {
callback(
null,
import_firestore2.BeginTransactionResponse.fromObject({
// dummy transaction id
transaction: Uint8Array.from([17, 2, 0, 0, 0, 0, 0, 0, 0])
})
);
}
Commit(call, callback) {
const date = /* @__PURE__ */ new Date();
try {
const results = call.request.writes.map((write) => {
return this.#state.writeV1Document(date, write);
});
callback(
null,
import_firestore2.CommitResponse.fromObject({
commit_time: TimestampFromDate(date),
write_results: results.map((result) => result.toObject())
})
);
} catch (err) {
if (err instanceof FirestoreEmulatorError) {
callback(
{
cause: err,
code: err.code,
message: err.message,
name: "Error"
},
null
);
return;
}
console.error(err);
callback(
{
cause: err,
message: "Something went wrong",
name: "Error"
},
null
);
}
}
Rollback(_call, callback) {
callback(null, import_empty.Empty.fromObject({}));
}
RunQuery(call) {
const date = /* @__PURE__ */ new Date();
const results = this.#state.v1Query(
call.request.parent,
call.request.structured_query
);
let transaction = call.request.transaction;
if (call.request.consistency_selector === "new_transaction") {
transaction = crypto.getRandomValues(new Uint8Array(12));
}
if (results.length > 0) {
results.forEach((result, i, arr) => {
call.write(
import_firestore2.RunQueryResponse.fromObject({
document: result.toV1DocumentObject(),
done: i === arr.length - 1,
read_time: TimestampFromDate(date),
skipped_results: 0,
transaction
})
);
});
} else {
call.write(
import_firestore2.RunQueryResponse.fromObject({
done: true,
read_time: TimestampFromDate(date),
skipped_results: 0,
transaction
})
);
}
call.end();
}
RunAggregationQuery(call) {
const date = TimestampFromNow();
const results = this.#state.v1Query(
call.request.parent,
call.request.structured_aggregation_query.structured_query
);
let transaction = call.request.transaction;
if (call.request.consistency_selector === "new_transaction") {
transaction = crypto.getRandomValues(new Uint8Array(12));
}
if (call.request.has_explain_options) {
const error = new Error(
"Explain for aggregation query is not supported."
);
console.error(error);
call.emit("error");
throw error;
}
const aggregateResult = Object.fromEntries(
call.request.structured_aggregation_query.aggregations.map((agg) => {
if (agg.has_count)
return [agg.alias, { integer_value: results.length }];
if (agg.has_sum) {
const sum = results.reduce((acc, cur) => {
const field = cur.getField(agg.sum.field.field_path);
if (!field) return acc;
if (field.type === "integer_value") return acc.add(field);
if (field.type === "double_value") return field.add(acc);
return acc;
}, new FirestoreStateDocumentIntegerField(0));
return [agg.alias, sum.toV1ValueObject()];
}
if (agg.has_avg) {
const sum = results.reduce((acc, cur) => {
const field = cur.getField(agg.avg.field.field_path);
if (!field) return acc;
if (field.type === "integer_value") return acc.add(field);
if (field.type === "double_value") return field.add(acc);
return acc;
}, new FirestoreStateDocumentIntegerField(0));
return [
agg.alias,
new FirestoreStateDocumentDoubleField(
sum.value / results.length
).toV1ValueObject()
];
}
return [
agg.alias,
new FirestoreStateDocumentNullField().toV1ValueObject()
];
})
);
const res = import_firestore2.RunAggregationQueryResponse.fromObject({
result: {
aggregate_fields: aggregateResult
},
read_time: date,
transaction
});
call.write(res);
call.end();
}
PartitionQuery(_call, _callback) {
console.error("Method<PartitionQuery> not implemented.");
throw new Error("Method<PartitionQuery> not implemented.");
}
Write(_call) {
console.error("Method<Write> not implemented.");
throw new Error("Method<Write> not implemented.");
}
Listen(call) {
call.once("data", (request) => {
if (!(request instanceof import_firestore2.ListenRequest)) {
console.error("Invalid request type");
call.end();
throw new Error("Invalid request type");
}
this.#state.v1Listen(
request,
(value) => {
call.write(value);
},
(handler) => {
call.once("end", handler);
}
);
});
}
ListCollectionIds(_call, _callback) {
console.error("Method<ListCollectionIds> not implemented.");
throw new Error("Method<ListCollectionIds> not implemented.");
}
BatchWrite(_call, _callback) {
console.error("Method<BatchWrite> not implemented.");
throw new Error("Method<BatchWrite> not implemented.");
}
CreateDocument(_call, _callback) {
console.error("Method<CreateDocument> not implemented.");
throw new Error("Method<CreateDocument> not implemented.");
}
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
FirestoreServiceV1Impl
});
//# sourceMappingURL=index.js.map