UNPKG

@firestore-emulator/server

Version:

This package is the implementation of the Firestore emulator. It is a Node.js

395 lines (388 loc) 13 kB
"use strict"; 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/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/error/error.ts var FirestoreEmulatorError = class extends Error { constructor(code, message) { super(message); this.code = code; } }; // 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