{"version":3,"sources":["../../../src/server/FirestoreServiceV1Impl/index.ts","../../../src/error/error.ts","../../../src/FirestoreState/index.ts","../../../src/FirestoreState/field.ts","../../../src/FirestoreState/mask.ts"],"sourcesContent":["import type { Document } from \"@firestore-emulator/proto/dist/google/firestore/v1/document\";\nimport type {\n  BatchGetDocumentsRequest,\n  BatchWriteRequest,\n  BatchWriteResponse,\n  BeginTransactionRequest,\n  CommitRequest,\n  CreateDocumentRequest,\n  DeleteDocumentRequest,\n  GetDocumentRequest,\n  ListCollectionIdsRequest,\n  ListCollectionIdsResponse,\n  ListDocumentsRequest,\n  ListDocumentsResponse,\n  ListenResponse,\n  PartitionQueryRequest,\n  PartitionQueryResponse,\n  RollbackRequest,\n  RunAggregationQueryRequest,\n  RunQueryRequest,\n  UpdateDocumentRequest,\n  WriteRequest,\n  WriteResponse,\n} from \"@firestore-emulator/proto/dist/google/firestore/v1/firestore\";\nimport {\n  BatchGetDocumentsResponse,\n  BeginTransactionResponse,\n  CommitResponse,\n  ListenRequest,\n  RunAggregationQueryResponse,\n  RunQueryResponse,\n  UnimplementedFirestoreService,\n} from \"@firestore-emulator/proto/dist/google/firestore/v1/firestore\";\nimport { Empty } from \"@firestore-emulator/proto/dist/google/protobuf/empty\";\nimport type {\n  ServerDuplexStream,\n  ServerUnaryCall,\n  ServerWritableStream,\n  sendUnaryData,\n  UntypedHandleCall,\n} from \"@grpc/grpc-js\";\nimport { FirestoreEmulatorError } from \"../../error/error\";\nimport type { FirestoreState } from \"../../FirestoreState\";\nimport { TimestampFromDate, TimestampFromNow } from \"../../FirestoreState\";\nimport {\n  FirestoreStateDocumentDoubleField,\n  FirestoreStateDocumentIntegerField,\n  FirestoreStateDocumentNullField,\n  type ValueObjectType,\n} from \"../../FirestoreState/field\";\n\nexport class FirestoreServiceV1Impl extends UnimplementedFirestoreService {\n  #state: FirestoreState;\n  constructor(state: FirestoreState) {\n    super();\n\n    this.#state = state;\n  }\n  override GetDocument(\n    _call: ServerUnaryCall<GetDocumentRequest, Document>,\n    _callback: sendUnaryData<Document>,\n  ): void {\n    console.error(\"Method<GetDocument> not implemented.\");\n    throw new Error(\"Method<GetDocument> not implemented.\");\n  }\n  override ListDocuments(\n    _call: ServerUnaryCall<ListDocumentsRequest, ListDocumentsResponse>,\n    _callback: sendUnaryData<ListDocumentsResponse>,\n  ): void {\n    console.error(\"Method<ListDocuments> not implemented.\");\n    throw new Error(\"Method<ListDocuments> not implemented.\");\n  }\n  override UpdateDocument(\n    _call: ServerUnaryCall<UpdateDocumentRequest, Document>,\n    _callback: sendUnaryData<Document>,\n  ): void {\n    console.error(\"Method<UpdateDocument> not implemented.\");\n    throw new Error(\"Method<UpdateDocument> not implemented.\");\n  }\n  override DeleteDocument(\n    _call: ServerUnaryCall<DeleteDocumentRequest, Empty>,\n    _callback: sendUnaryData<Empty>,\n  ): void {\n    console.error(\"Method<DeleteDocument> not implemented.\");\n    throw new Error(\"Method<DeleteDocument> not implemented.\");\n  }\n  override BatchGetDocuments(\n    call: ServerWritableStream<\n      BatchGetDocumentsRequest,\n      BatchGetDocumentsResponse\n    >,\n  ): void {\n    const date = TimestampFromNow();\n    const tx = call.request.has_new_transaction\n      ? Uint8Array.from([17, 2, 0, 0, 0, 0, 0, 0, 0])\n      : null;\n    if (tx) {\n      call.write(\n        BatchGetDocumentsResponse.fromObject({\n          transaction: tx,\n        }),\n      );\n    }\n    for (const documentPath of call.request.documents) {\n      const document = this.#state.getDocument(documentPath);\n      call.write(\n        BatchGetDocumentsResponse.fromObject({\n          found: document.metadata.hasExist\n            ? document.toV1DocumentObject()\n            : undefined,\n          missing: document.metadata.hasExist ? undefined : documentPath,\n          read_time: date,\n        }),\n      );\n    }\n\n    call.end();\n  }\n  override BeginTransaction(\n    _call: ServerUnaryCall<BeginTransactionRequest, BeginTransactionResponse>,\n    callback: sendUnaryData<BeginTransactionResponse>,\n  ): void {\n    callback(\n      null,\n      BeginTransactionResponse.fromObject({\n        // dummy transaction id\n        transaction: Uint8Array.from([17, 2, 0, 0, 0, 0, 0, 0, 0]),\n      }),\n    );\n  }\n\n  override Commit(\n    call: ServerUnaryCall<CommitRequest, CommitResponse>,\n    callback: sendUnaryData<CommitResponse>,\n  ): void {\n    const date = new Date();\n    try {\n      const results = call.request.writes.map((write) => {\n        return this.#state.writeV1Document(date, write);\n      });\n      callback(\n        null,\n        CommitResponse.fromObject({\n          commit_time: TimestampFromDate(date),\n          write_results: results.map((result) => result.toObject()),\n        }),\n      );\n    } catch (err) {\n      if (err instanceof FirestoreEmulatorError) {\n        callback(\n          {\n            cause: err,\n            code: err.code,\n            message: err.message,\n            name: \"Error\",\n          },\n          null,\n        );\n        return;\n      }\n      console.error(err);\n      callback(\n        {\n          cause: err,\n          message: \"Something went wrong\",\n          name: \"Error\",\n        },\n        null,\n      );\n    }\n  }\n  override Rollback(\n    _call: ServerUnaryCall<RollbackRequest, Empty>,\n    callback: sendUnaryData<Empty>,\n  ): void {\n    callback(null, Empty.fromObject({}));\n  }\n  override RunQuery(\n    call: ServerWritableStream<RunQueryRequest, RunQueryResponse>,\n  ): void {\n    const date = new Date();\n    const results = this.#state.v1Query(\n      call.request.parent,\n      call.request.structured_query,\n    );\n\n    let transaction: Uint8Array | undefined = call.request.transaction;\n    if (call.request.consistency_selector === \"new_transaction\") {\n      transaction = crypto.getRandomValues(new Uint8Array(12));\n    }\n\n    if (results.length > 0) {\n      results.forEach((result, i, arr) => {\n        call.write(\n          RunQueryResponse.fromObject({\n            document: result.toV1DocumentObject(),\n            done: i === arr.length - 1,\n            read_time: TimestampFromDate(date),\n            skipped_results: 0,\n            transaction,\n          }),\n        );\n      });\n    } else {\n      call.write(\n        RunQueryResponse.fromObject({\n          done: true,\n          read_time: TimestampFromDate(date),\n          skipped_results: 0,\n          transaction,\n        }),\n      );\n    }\n\n    call.end();\n  }\n  override RunAggregationQuery(\n    call: ServerWritableStream<\n      RunAggregationQueryRequest,\n      RunAggregationQueryResponse\n    >,\n  ): void {\n    const date = TimestampFromNow();\n    const results = this.#state.v1Query(\n      call.request.parent,\n      call.request.structured_aggregation_query.structured_query,\n    );\n    let transaction: Uint8Array | undefined = call.request.transaction;\n    if (call.request.consistency_selector === \"new_transaction\") {\n      transaction = crypto.getRandomValues(new Uint8Array(12));\n    }\n    if (call.request.has_explain_options) {\n      const error = new Error(\n        \"Explain for aggregation query is not supported.\",\n      );\n      console.error(error);\n      call.emit(\"error\");\n      throw error;\n    }\n\n    const aggregateResult = Object.fromEntries(\n      call.request.structured_aggregation_query.aggregations.map<\n        [string, ValueObjectType]\n      >((agg) => {\n        if (agg.has_count)\n          return [agg.alias, { integer_value: results.length }];\n        if (agg.has_sum) {\n          const sum = results.reduce<\n            | FirestoreStateDocumentIntegerField\n            | FirestoreStateDocumentDoubleField\n          >((acc, cur) => {\n            const field = cur.getField(agg.sum.field.field_path);\n            if (!field) return acc;\n            if (field.type === \"integer_value\") return acc.add(field);\n            if (field.type === \"double_value\") return field.add(acc);\n            return acc;\n          }, new FirestoreStateDocumentIntegerField(0));\n          return [agg.alias, sum.toV1ValueObject()];\n        }\n        if (agg.has_avg) {\n          const sum = results.reduce<\n            | FirestoreStateDocumentIntegerField\n            | FirestoreStateDocumentDoubleField\n          >((acc, cur) => {\n            const field = cur.getField(agg.avg.field.field_path);\n            if (!field) return acc;\n            if (field.type === \"integer_value\") return acc.add(field);\n            if (field.type === \"double_value\") return field.add(acc);\n            return acc;\n          }, new FirestoreStateDocumentIntegerField(0));\n          return [\n            agg.alias,\n            new FirestoreStateDocumentDoubleField(\n              sum.value / results.length,\n            ).toV1ValueObject(),\n          ];\n        }\n        return [\n          agg.alias,\n          new FirestoreStateDocumentNullField().toV1ValueObject(),\n        ];\n      }),\n    );\n    const res = RunAggregationQueryResponse.fromObject({\n      result: {\n        aggregate_fields: aggregateResult,\n      },\n      read_time: date,\n      transaction,\n    });\n    call.write(res);\n    call.end();\n  }\n  override PartitionQuery(\n    _call: ServerUnaryCall<PartitionQueryRequest, PartitionQueryResponse>,\n    _callback: sendUnaryData<PartitionQueryResponse>,\n  ): void {\n    console.error(\"Method<PartitionQuery> not implemented.\");\n    throw new Error(\"Method<PartitionQuery> not implemented.\");\n  }\n  override Write(_call: ServerDuplexStream<WriteRequest, WriteResponse>): void {\n    console.error(\"Method<Write> not implemented.\");\n    throw new Error(\"Method<Write> not implemented.\");\n  }\n  override Listen(\n    call: ServerDuplexStream<ListenRequest, ListenResponse>,\n  ): void {\n    call.once(\"data\", (request) => {\n      if (!(request instanceof ListenRequest)) {\n        console.error(\"Invalid request type\");\n        call.end();\n        throw new Error(\"Invalid request type\");\n      }\n      this.#state.v1Listen(\n        request,\n        (value) => {\n          call.write(value);\n        },\n        (handler) => {\n          call.once(\"end\", handler);\n        },\n      );\n    });\n  }\n  override ListCollectionIds(\n    _call: ServerUnaryCall<ListCollectionIdsRequest, ListCollectionIdsResponse>,\n    _callback: sendUnaryData<ListCollectionIdsResponse>,\n  ): void {\n    console.error(\"Method<ListCollectionIds> not implemented.\");\n    throw new Error(\"Method<ListCollectionIds> not implemented.\");\n  }\n  override BatchWrite(\n    _call: ServerUnaryCall<BatchWriteRequest, BatchWriteResponse>,\n    _callback: sendUnaryData<BatchWriteResponse>,\n  ): void {\n    console.error(\"Method<BatchWrite> not implemented.\");\n    throw new Error(\"Method<BatchWrite> not implemented.\");\n  }\n  override CreateDocument(\n    _call: ServerUnaryCall<CreateDocumentRequest, Document>,\n    _callback: sendUnaryData<Document>,\n  ): void {\n    console.error(\"Method<CreateDocument> not implemented.\");\n    throw new Error(\"Method<CreateDocument> not implemented.\");\n  }\n\n  [name: string]: UntypedHandleCall;\n}\n","import type { Status } from \"@grpc/grpc-js/build/src/constants\";\n\nexport class FirestoreEmulatorError extends Error {\n  constructor(\n    readonly code: Status,\n    message: string,\n  ) {\n    super(message);\n  }\n}\n","import { EventEmitter } from \"node:events\";\n\nimport { Document as v1Document } from \"@firestore-emulator/proto/dist/google/firestore/v1/document\";\nimport type { ListenRequest as v1ListenRequest } from \"@firestore-emulator/proto/dist/google/firestore/v1/firestore\";\nimport {\n  ListenResponse as v1ListenResponse,\n  TargetChangeTargetChangeType as v1TargetChangeTargetChangeType,\n} from \"@firestore-emulator/proto/dist/google/firestore/v1/firestore\";\nimport type {\n  StructuredQuery as v1StructuredQuery,\n  StructuredQueryFieldFilter as v1StructuredQueryFieldFilter,\n} from \"@firestore-emulator/proto/dist/google/firestore/v1/query\";\nimport {\n  StructuredQueryCompositeFilterOperator as v1StructuredQueryCompositeFilterOperator,\n  StructuredQueryDirection as v1StructuredQueryDirection,\n  StructuredQueryFieldFilterOperator as v1StructuredQueryFieldFilterOperator,\n} from \"@firestore-emulator/proto/dist/google/firestore/v1/query\";\nimport type {\n  DocumentTransformFieldTransform as v1DocumentTransformFieldTransform,\n  Write as v1Write,\n} from \"@firestore-emulator/proto/dist/google/firestore/v1/write\";\nimport {\n  DocumentTransformFieldTransformServerValue,\n  WriteResult as v1WriteResult,\n} from \"@firestore-emulator/proto/dist/google/firestore/v1/write\";\nimport { Timestamp } from \"@firestore-emulator/proto/dist/google/protobuf/timestamp\";\nimport { Status } from \"@grpc/grpc-js/build/src/constants\";\nimport { assertNever } from \"assert-never\";\nimport { produce } from \"immer\";\nimport type { TypeSafeEventEmitter } from \"typesafe-event-emitter\";\n\nimport { FirestoreEmulatorError } from \"../error/error\";\nimport { isNotNull } from \"../utils\";\n\nimport type { FirestoreStateDocumentFields } from \"./field\";\nimport {\n  convertV1DocumentField,\n  convertV1Value,\n  FirestoreStateDocumentArrayField,\n  FirestoreStateDocumentDoubleField,\n  FirestoreStateDocumentIntegerField,\n  FirestoreStateDocumentTimestampField,\n} from \"./field\";\nimport { updateFields } from \"./mask\";\n\ninterface Events {\n  \"add-collection\": { collection: FirestoreStateCollection };\n  \"add-database\": { database: FirestoreStateDatabase };\n  \"add-document\": { document: FirestoreStateDocument };\n  \"add-project\": { project: FirestoreStateProject };\n  \"clear-all-projects\": Record<string, never>;\n  \"create-document\": { document: FirestoreStateDocument };\n  \"delete-document\": { document: FirestoreStateDocument };\n  \"update-document\": { document: FirestoreStateDocument };\n}\n\nexport interface HasCollections {\n  getCollection(collectionName: string): FirestoreStateCollection;\n  getPath(): string;\n}\n\ntype FirestoreStateDocumentMetadata =\n  | {\n      createdAt: null;\n      hasExist: false;\n      updatedAt: null;\n    }\n  | {\n      createdAt: Date;\n      hasExist: true;\n      updatedAt: Date;\n    };\n\nexport class FirestoreStateDocument implements HasCollections {\n  metadata: FirestoreStateDocumentMetadata = {\n    createdAt: null,\n    hasExist: false,\n    updatedAt: null,\n  };\n  constructor(\n    private emitter: TypeSafeEventEmitter<Events>,\n    readonly database: FirestoreStateDatabase,\n    readonly parent: FirestoreStateCollection,\n    readonly name: string,\n    private fields: Record<string, FirestoreStateDocumentFields>,\n    private collections: Record<string, FirestoreStateCollection>,\n  ) {}\n\n  iterateFromRoot() {\n    const iters: FirestoreStateDocument[] = [this];\n    let current: FirestoreStateDocument = this;\n    while (current.parent.parent instanceof FirestoreStateDocument) {\n      const next = current.parent.parent;\n      current = next;\n      iters.push(current);\n    }\n    return iters.slice().reverse();\n  }\n\n  hasChild(): boolean {\n    for (const collection of Object.values(this.collections)) {\n      if (collection.hasChild()) return true;\n    }\n    return false;\n  }\n\n  getCollection(collectionName: string) {\n    this.collections = produce(this.collections, (draft) => {\n      if (!(collectionName in draft)) {\n        const collection = new FirestoreStateCollection(\n          this.emitter,\n          this.database,\n          this,\n          collectionName,\n          {},\n        );\n        draft[collectionName] = collection;\n        this.emitter.emit(\"add-collection\", { collection });\n      }\n    });\n\n    const collection = this.collections[collectionName];\n    if (!collection) {\n      throw new Error(`Collection<${collectionName}> not found.`);\n    }\n    return collection;\n  }\n\n  toV1Document(): v1Document {\n    return v1Document.fromObject({\n      create_time: this.metadata.hasExist\n        ? Timestamp.fromObject({\n            nanos: this.metadata.createdAt.getMilliseconds() * 1000 * 1000,\n            seconds: Math.floor(this.metadata.createdAt.getTime() / 1000),\n          })\n        : undefined,\n      fields: Object.fromEntries(\n        Object.entries(this.fields).map(([key, field]) => [\n          key,\n          field.toV1ValueObject(),\n        ]),\n      ),\n      name: this.getPath(),\n      update_time: this.metadata.hasExist\n        ? Timestamp.fromObject({\n            nanos: this.metadata.updatedAt.getMilliseconds() * 1000 * 1000,\n            seconds: Math.floor(this.metadata.updatedAt.getTime() / 1000),\n          })\n        : undefined,\n    });\n  }\n\n  toV1DocumentObject(): ReturnType<typeof v1Document.prototype.toObject> {\n    const document = this.toV1Document();\n    return {\n      create_time: document.create_time.toObject(),\n      fields: Object.fromEntries(\n        Array.from(document.fields).map(([key, value]) => [\n          key,\n          convertV1Value(value),\n        ]),\n      ),\n      name: document.name,\n      update_time: document.update_time.toObject(),\n    };\n  }\n\n  toJSON(): {\n    collections: Record<string, ReturnType<FirestoreStateCollection[\"toJSON\"]>>;\n    fields: Record<string, ReturnType<FirestoreStateDocumentFields[\"toJSON\"]>>;\n    path: string;\n  } {\n    return {\n      collections: Object.fromEntries(\n        Object.entries(this.collections)\n          .filter(([, collection]) => collection.hasChild())\n          .map(([key, collection]) => [key, collection.toJSON()]),\n      ),\n      fields: Object.fromEntries(\n        Object.entries(this.fields).map(([key, field]) => [\n          key,\n          field.toJSON(),\n        ]),\n      ),\n      path: this.getPath(),\n    };\n  }\n\n  create(date: Date, fields: Record<string, FirestoreStateDocumentFields>) {\n    if (this.metadata.hasExist) {\n      throw new Error(\"Document already exists.\");\n    }\n    this.metadata = produce<\n      FirestoreStateDocumentMetadata,\n      FirestoreStateDocumentMetadata\n    >(this.metadata, (draft) => {\n      draft.hasExist = true;\n      draft.createdAt = date;\n      draft.updatedAt = date;\n    });\n    this.fields = produce(this.fields, (draft) => {\n      for (const [key, field] of Object.entries(fields)) {\n        draft[key] = field;\n      }\n    });\n    this.emitter.emit(\"create-document\", { document: this });\n  }\n\n  update(\n    date: Date,\n    fields: Record<string, FirestoreStateDocumentFields>,\n    updateMask: string[] = [],\n  ) {\n    if (!this.metadata.hasExist) {\n      throw new Error(\"Document does not exist.\");\n    }\n    this.metadata = produce<\n      FirestoreStateDocumentMetadata,\n      FirestoreStateDocumentMetadata\n    >(this.metadata, (draft) => {\n      draft.updatedAt = date;\n    });\n    this.fields = updateFields(this.fields, fields, updateMask);\n    this.emitter.emit(\"update-document\", { document: this });\n  }\n\n  set(\n    date: Date,\n    fields: Record<string, FirestoreStateDocumentFields>,\n    updateMask: string[] = [],\n  ) {\n    const isCreate = !this.metadata.hasExist;\n    if (!this.metadata.hasExist) {\n      this.metadata = produce<\n        FirestoreStateDocumentMetadata,\n        FirestoreStateDocumentMetadata\n      >(this.metadata, (draft) => {\n        draft.hasExist = true;\n        draft.createdAt = date;\n        draft.updatedAt = date;\n      });\n    } else {\n      this.metadata = produce<\n        FirestoreStateDocumentMetadata,\n        FirestoreStateDocumentMetadata\n      >(this.metadata, (draft) => {\n        draft.updatedAt = date;\n      });\n    }\n\n    this.fields = updateFields(this.fields, fields, updateMask);\n    if (isCreate) {\n      this.emitter.emit(\"create-document\", { document: this });\n    } else {\n      this.emitter.emit(\"update-document\", { document: this });\n    }\n  }\n\n  delete() {\n    if (!this.metadata.hasExist) {\n      throw new Error(\"Document does not exist.\");\n    }\n    this.metadata = produce<\n      FirestoreStateDocumentMetadata,\n      FirestoreStateDocumentMetadata\n    >(this.metadata, (draft) => {\n      draft.hasExist = false;\n      draft.createdAt = null;\n      draft.updatedAt = null;\n    });\n    this.fields = produce(this.fields, (draft) => {\n      for (const key of Object.keys(draft)) {\n        delete draft[key];\n      }\n    });\n    this.emitter.emit(\"delete-document\", { document: this });\n  }\n\n  getField(path: string) {\n    if (path.includes(\".\")) {\n      throw new Error(\"Not implemented\");\n    }\n    return this.fields[path];\n  }\n\n  getPath(): string {\n    return `${this.parent.getPath()}/${this.name}`;\n  }\n\n  getDocumentPath(): string {\n    return `${this.parent.getDocumentPath()}/${this.name}`;\n  }\n\n  v1Transform(date: Date, transforms: v1DocumentTransformFieldTransform[]) {\n    for (const transform of transforms) {\n      const field = this.getField(transform.field_path);\n      if (transform.has_increment) {\n        if (transform.increment.has_integer_value) {\n          if (!field) {\n            this.set(date, {\n              [transform.field_path]: new FirestoreStateDocumentIntegerField(\n                transform.increment.integer_value,\n              ),\n            });\n            continue;\n          }\n          if (field instanceof FirestoreStateDocumentIntegerField) {\n            this.set(date, {\n              [transform.field_path]: new FirestoreStateDocumentIntegerField(\n                field.value + transform.increment.integer_value,\n              ),\n            });\n            continue;\n          }\n          if (field instanceof FirestoreStateDocumentDoubleField) {\n            this.set(date, {\n              [transform.field_path]: new FirestoreStateDocumentDoubleField(\n                field.value + transform.increment.integer_value,\n              ),\n            });\n            continue;\n          }\n          throw new Error(\n            `Invalid transform: ${JSON.stringify(\n              transform,\n            )}. increment transform can only be applied to an integer or a double field`,\n          );\n        }\n        if (transform.increment.has_double_value) {\n          if (!field) {\n            this.set(date, {\n              [transform.field_path]: new FirestoreStateDocumentDoubleField(\n                transform.increment.double_value,\n              ),\n            });\n            continue;\n          }\n          if (\n            field instanceof FirestoreStateDocumentIntegerField ||\n            field instanceof FirestoreStateDocumentDoubleField\n          ) {\n            this.set(date, {\n              [transform.field_path]: new FirestoreStateDocumentDoubleField(\n                field.value + transform.increment.double_value,\n              ),\n            });\n            continue;\n          }\n          throw new Error(\n            `Invalid transform: ${JSON.stringify(\n              transform,\n            )}. increment transform can only be applied to an integer or a double field`,\n          );\n        }\n        throw new Error(\n          `Invalid transform: ${JSON.stringify(\n            transform,\n          )}. increment transform can only be applied to an integer or a double field`,\n        );\n      }\n      if (transform.has_remove_all_from_array) {\n        const removeFields = transform.remove_all_from_array.values.map(\n          convertV1DocumentField,\n        );\n        if (field instanceof FirestoreStateDocumentArrayField) {\n          const removedFields = field.value.filter(\n            (value) =>\n              !removeFields.some((removeField) => removeField.eq(value)),\n          );\n          this.set(date, {\n            [transform.field_path]: new FirestoreStateDocumentArrayField(\n              removedFields,\n            ),\n          });\n          return;\n        }\n      }\n      if (transform.has_append_missing_elements) {\n        const appendFields = transform.append_missing_elements.values.map(\n          convertV1DocumentField,\n        );\n        if (field instanceof FirestoreStateDocumentArrayField) {\n          const appendedFields = [\n            ...field.value,\n            ...appendFields.filter(\n              (appendField) =>\n                !field.value.some((value) => value.eq(appendField)),\n            ),\n          ];\n          this.set(date, {\n            [transform.field_path]: new FirestoreStateDocumentArrayField(\n              appendedFields,\n            ),\n          });\n          return;\n        }\n      }\n      if (transform.has_set_to_server_value) {\n        if (\n          transform.set_to_server_value ===\n          DocumentTransformFieldTransformServerValue.REQUEST_TIME\n        ) {\n          this.set(date, {\n            [transform.field_path]:\n              FirestoreStateDocumentTimestampField.fromDate(date),\n          });\n          return;\n        }\n        throw new Error(\n          `Invalid transform: ${JSON.stringify(\n            transform,\n          )}. set_to_server_value must be a valid value`,\n        );\n      }\n      throw new Error(\n        `Invalid transform: ${JSON.stringify(transform.toObject(), null, 4)}`,\n      );\n    }\n  }\n}\n\nexport class FirestoreStateCollection {\n  constructor(\n    private emitter: TypeSafeEventEmitter<Events>,\n    readonly database: FirestoreStateDatabase,\n    readonly parent: FirestoreStateDocument | FirestoreStateDatabase,\n    readonly name: string,\n    private documents: Record<string, FirestoreStateDocument>,\n  ) {}\n\n  getDocument(documentName: string) {\n    this.documents = produce(this.documents, (draft) => {\n      if (!(documentName in draft)) {\n        const document = new FirestoreStateDocument(\n          this.emitter,\n          this.database,\n          this,\n          documentName,\n          {},\n          {},\n        );\n        draft[documentName] = document;\n      }\n    });\n\n    const document = this.documents[documentName];\n    if (!document) {\n      throw new Error(`Document<${documentName}> not found.`);\n    }\n    return document;\n  }\n\n  hasChild(): boolean {\n    for (const document of Object.values(this.documents)) {\n      if (document.metadata.hasExist) return true;\n      if (document.hasChild()) return true;\n    }\n    return false;\n  }\n\n  getAllDocuments() {\n    return Object.values(this.documents);\n  }\n\n  toJSON() {\n    return {\n      documents: Object.fromEntries(\n        Object.entries(this.documents)\n          .filter(\n            ([, document]) => document.metadata.hasExist || document.hasChild(),\n          )\n          .map(([key, document]) => [key, document.toJSON()]),\n      ),\n      path: this.getPath(),\n    };\n  }\n\n  getPath(): string {\n    return `${this.parent.getPath()}/${this.name}`;\n  }\n\n  getDocumentPath(): string {\n    if (this.parent instanceof FirestoreStateDatabase) return this.name;\n    return `${this.parent.getDocumentPath()}/${this.name}`;\n  }\n}\n\nexport class FirestoreStateDatabase implements HasCollections {\n  constructor(\n    private emitter: TypeSafeEventEmitter<Events>,\n    readonly project: FirestoreStateProject,\n    readonly name: string,\n    private collections: Record<string, FirestoreStateCollection>,\n  ) {}\n\n  getCollection(collectionName: string) {\n    this.collections = produce(this.collections, (draft) => {\n      if (!(collectionName in draft)) {\n        const collection = new FirestoreStateCollection(\n          this.emitter,\n          this,\n          this,\n          collectionName,\n          {},\n        );\n        draft[collectionName] = collection;\n        this.emitter.emit(\"add-collection\", { collection });\n      }\n    });\n\n    const collection = this.collections[collectionName];\n    if (!collection) {\n      throw new Error(`Collection<${collectionName}> not found.`);\n    }\n    return collection;\n  }\n\n  toJSON() {\n    return {\n      collections: Object.fromEntries(\n        Object.entries(this.collections).map(([key, collection]) => [\n          key,\n          collection.toJSON(),\n        ]),\n      ),\n      path: this.getPath(),\n    };\n  }\n\n  getPath(): string {\n    return `${this.project.getPath()}/databases/${this.name}/documents`;\n  }\n}\n\nexport class FirestoreStateProject {\n  constructor(\n    private emitter: TypeSafeEventEmitter<Events>,\n    readonly name: string,\n    private databases: Record<string, FirestoreStateDatabase>,\n  ) {}\n\n  toJSON() {\n    return {\n      databases: Object.fromEntries(\n        Object.entries(this.databases).map(([key, database]) => [\n          key,\n          database.toJSON(),\n        ]),\n      ),\n      path: this.getPath(),\n    };\n  }\n\n  getPath(): string {\n    return `projects/${this.name}`;\n  }\n\n  getDatabase(databaseName: string) {\n    this.databases = produce(this.databases, (draft) => {\n      if (!(databaseName in draft)) {\n        const database = new FirestoreStateDatabase(\n          this.emitter,\n          this,\n          databaseName,\n          {},\n        );\n        draft[databaseName] = database;\n        this.emitter.emit(\"add-database\", { database });\n      }\n    });\n\n    const database = this.databases[databaseName];\n    if (!database) {\n      throw new Error(`Database<${databaseName}> not found.`);\n    }\n    return database;\n  }\n}\n\nexport const TimestampFromDate = (date: Date) =>\n  Timestamp.fromObject({\n    nanos: (date.getTime() % 1000) * 1000 * 1000,\n    seconds: Math.floor(date.getTime() / 1000),\n  });\nexport const DateFromTimestamp = (timestamp: Timestamp) =>\n  new Date(timestamp.seconds * 1000 + timestamp.nanos / 1000 / 1000);\n\nexport const TimestampFromNow = () => TimestampFromDate(new Date());\n\nconst v1FilterDocuments = (\n  field: FirestoreStateDocumentFields,\n  filter: v1StructuredQueryFieldFilter,\n) => {\n  const filterValue = convertV1DocumentField(filter.value);\n  if (!filter.field.field_path) {\n    throw new Error(\"field_path is required\");\n  }\n  switch (filter.op) {\n    case v1StructuredQueryFieldFilterOperator.EQUAL:\n      return field.eq(filterValue);\n    case v1StructuredQueryFieldFilterOperator.LESS_THAN:\n      return field.lt(filterValue);\n    case v1StructuredQueryFieldFilterOperator.LESS_THAN_OR_EQUAL:\n      return field.lte(filterValue);\n    case v1StructuredQueryFieldFilterOperator.GREATER_THAN:\n      return field.gt(filterValue);\n    case v1StructuredQueryFieldFilterOperator.GREATER_THAN_OR_EQUAL:\n      return field.gte(filterValue);\n    case v1StructuredQueryFieldFilterOperator.ARRAY_CONTAINS:\n      return (\n        field instanceof FirestoreStateDocumentArrayField &&\n        field.value.some((value) => value.eq(filterValue))\n      );\n    case v1StructuredQueryFieldFilterOperator.ARRAY_CONTAINS_ANY:\n      return (\n        field instanceof FirestoreStateDocumentArrayField &&\n        filterValue instanceof FirestoreStateDocumentArrayField &&\n        field.value.some((value) =>\n          filterValue.value.some((filterValue) => value.eq(filterValue)),\n        )\n      );\n    case v1StructuredQueryFieldFilterOperator.IN:\n      return (\n        filterValue instanceof FirestoreStateDocumentArrayField &&\n        filterValue.value.some((value) => field.eq(value))\n      );\n    case v1StructuredQueryFieldFilterOperator.NOT_EQUAL:\n      return !field.eq(filterValue);\n    case v1StructuredQueryFieldFilterOperator.NOT_IN:\n      return (\n        filterValue instanceof FirestoreStateDocumentArrayField &&\n        filterValue.value.every((value) => !field.eq(value))\n      );\n    case v1StructuredQueryFieldFilterOperator.OPERATOR_UNSPECIFIED: {\n      throw new Error(\n        `Invalid query: op is not supported yet, ${\n          v1StructuredQueryFieldFilterOperator[filter.op]\n        }`,\n      );\n    }\n    case undefined:\n      throw new Error(\"Invalid query: op is required\");\n    default:\n      assertNever(filter.op);\n  }\n};\n\nexport class FirestoreState {\n  readonly emitter: TypeSafeEventEmitter<Events>;\n  constructor(private projects: Record<string, FirestoreStateProject> = {}) {\n    this.emitter = new EventEmitter();\n  }\n\n  toJSON() {\n    return {\n      projects: Object.fromEntries(\n        Object.entries(this.projects).map(([key, project]) => [\n          key,\n          project.toJSON(),\n        ]),\n      ),\n    };\n  }\n\n  getProject(projectName: string) {\n    this.projects = produce(this.projects, (draft) => {\n      if (!(projectName in draft)) {\n        const project = new FirestoreStateProject(\n          this.emitter,\n          projectName,\n          {},\n        );\n        draft[projectName] = project;\n        this.emitter.emit(\"add-project\", { project });\n      }\n    });\n\n    const project = this.projects[projectName];\n    if (!project) {\n      throw new Error(`Project<${projectName}> not found.`);\n    }\n    return project;\n  }\n\n  getCollection(path: string) {\n    const [\n      project,\n      projectName,\n      database,\n      databaseName,\n      documents,\n      collectionName,\n      ...rest\n    ] = path.split(\"/\");\n    if (\n      project !== \"projects\" ||\n      typeof projectName !== \"string\" ||\n      database !== \"databases\" ||\n      typeof databaseName !== \"string\" ||\n      documents !== \"documents\" ||\n      typeof collectionName !== \"string\" ||\n      rest.length % 2 !== 0\n    ) {\n      throw new Error(`Invalid path: ${path}`);\n    }\n\n    let current = this.getProject(projectName)\n      .getDatabase(databaseName)\n      .getCollection(collectionName);\n    let next = rest;\n    while (next.length > 0) {\n      const [documentId, collectionName, ...rest] = next;\n      if (\n        typeof collectionName !== \"string\" ||\n        typeof documentId !== \"string\"\n      ) {\n        throw new Error(`Invalid path: ${path}`);\n      }\n      current = current.getDocument(documentId).getCollection(collectionName);\n      next = rest;\n    }\n    return current;\n  }\n\n  getDocument(path: string) {\n    const [docId, ...rest] = path.split(\"/\").reverse();\n    const collection = this.getCollection(rest.slice().reverse().join(\"/\"));\n\n    if (typeof docId !== \"string\") {\n      throw new Error(`Invalid path: ${path}`);\n    }\n    return collection.getDocument(docId);\n  }\n\n  clear() {\n    this.projects = {};\n    this.emitter.emit(\"clear-all-projects\", {});\n  }\n\n  writeV1Document(date: Date, write: v1Write): v1WriteResult {\n    const writeTime = TimestampFromDate(date);\n    if (write.has_delete) {\n      const document = this.getDocument(write.delete);\n      if (write.has_current_document && write.current_document.has_exists) {\n        // 存在確認を行う\n        if (write.current_document.exists) {\n          if (!document.metadata.hasExist) {\n            throw new FirestoreEmulatorError(\n              Status.NOT_FOUND,\n              `no entity to update: app: \"dev~${document.database.project.name}\"\npath <\n${document\n  .iterateFromRoot()\n  .map(\n    (doc) =>\n      `  Element {\n    type: \"${doc.parent.name}\"\n    name: \"${doc.name}\"\n  }`,\n  )\n  .join(\"\\n\")}\n>\n`,\n            );\n          }\n        } else {\n          if (document.metadata.hasExist) {\n            throw new FirestoreEmulatorError(\n              Status.ALREADY_EXISTS,\n              `entity already exists: EntityRef{partitionRef=dev~${\n                document.database.project.name\n              }, path=/${document.getDocumentPath()}}`,\n            );\n          }\n        }\n      }\n      if (document.metadata.hasExist) {\n        document.delete();\n      }\n      return v1WriteResult.fromObject({\n        transform_results: [],\n        update_time: writeTime,\n      });\n    }\n    if (write.has_update) {\n      if (write.update.has_create_time) {\n        throw new Error(\"update.create_time is not implemented\");\n      }\n      if (write.update.has_update_time) {\n        throw new Error(\"update.update_time is not implemented\");\n      }\n      const { name, fields } = write.update;\n      const document = this.getDocument(name);\n      if (write.has_current_document && write.current_document.has_exists) {\n        if (!write.current_document.exists) {\n          if (document.metadata.hasExist) {\n            throw new FirestoreEmulatorError(\n              Status.ALREADY_EXISTS,\n              `entity already exists: EntityRef{partitionRef=dev~${\n                document.database.project.name\n              }, path=/${document.getDocumentPath()}}`,\n            );\n          }\n\n          document.create(\n            date,\n            Object.fromEntries(\n              Array.from(fields.entries()).map(([key, field]) => [\n                key,\n                convertV1DocumentField(field),\n              ]),\n            ),\n          );\n          document.v1Transform(date, write.update_transforms);\n        } else {\n          if (!document.metadata.hasExist) {\n            throw new FirestoreEmulatorError(\n              Status.NOT_FOUND,\n              `no entity to update: app: \"dev~${document.database.project.name}\"\npath <\n${document\n  .iterateFromRoot()\n  .map(\n    (doc) =>\n      `  Element {\n    type: \"${doc.parent.name}\"\n    name: \"${doc.name}\"\n  }`,\n  )\n  .join(\"\\n\")}\n>\n`,\n            );\n          }\n\n          document.update(\n            date,\n            Object.fromEntries(\n              Array.from(fields.entries()).map(([key, field]) => [\n                key,\n                convertV1DocumentField(field),\n              ]),\n            ),\n            write.update_mask?.field_paths,\n          );\n          document.v1Transform(date, write.update_transforms);\n        }\n      } else {\n        document.set(\n          date,\n          Object.fromEntries(\n            Array.from(fields.entries()).map(([key, field]) => [\n              key,\n              convertV1DocumentField(field),\n            ]),\n          ),\n          write.update_mask?.field_paths,\n        );\n        document.v1Transform(date, write.update_transforms);\n      }\n\n      return v1WriteResult.fromObject({\n        transform_results: [],\n        update_time: writeTime,\n      });\n    }\n    throw new Error(\"Invalid write\");\n  }\n\n  v1Query(parent: string, query: v1StructuredQuery) {\n    if (query.from.length !== 1) {\n      throw new Error(\"query.from.length must be 1\");\n    }\n    const { collection_id } = query.from[0] ?? {};\n    if (!collection_id) {\n      throw new Error(\"collection_id is not supported\");\n    }\n    const collectionName = `${parent}/${collection_id}`;\n    const collection = this.getCollection(collectionName);\n    let docs = collection.getAllDocuments().filter((v) => v.metadata.hasExist);\n\n    docs = docs.slice().sort((aDocument, bDocument) => {\n      for (const { field, direction } of query.order_by) {\n        const a = aDocument.getField(field.field_path);\n        const b = bDocument.getField(field.field_path);\n        if (!a || !b) {\n          if (a && !b) return -1;\n          if (!a && b) return 1;\n          continue;\n        }\n        if (a.eq(b)) continue;\n        if (direction === v1StructuredQueryDirection.ASCENDING) {\n          if (a.lt(b)) return -1;\n          if (b.lt(a)) return 1;\n        } else if (direction === v1StructuredQueryDirection.DESCENDING) {\n          if (a.lt(b)) return 1;\n          if (b.lt(a)) return -1;\n        }\n      }\n      return 0;\n    });\n\n    if (query.has_where) {\n      if (query.where.has_field_filter) {\n        const filter = query.where.field_filter;\n\n        docs = docs.filter((document) => {\n          if (!filter.field.field_path) {\n            throw new Error(\"field_path is required\");\n          }\n          const field = document.getField(filter.field.field_path);\n          if (!field) return false;\n          return v1FilterDocuments(field, filter);\n        });\n      }\n      if (query.where.has_composite_filter) {\n        switch (query.where.composite_filter.op) {\n          case v1StructuredQueryCompositeFilterOperator.AND:\n          case v1StructuredQueryCompositeFilterOperator.OR:\n            break;\n          case v1StructuredQueryCompositeFilterOperator.OPERATOR_UNSPECIFIED:\n            throw new Error(\"Invalid query: op is required\");\n          default:\n            assertNever(query.where.composite_filter.op);\n        }\n\n        docs = docs.filter((document) => {\n          if (\n            query.where.composite_filter.op ===\n            v1StructuredQueryCompositeFilterOperator.AND\n          ) {\n            return query.where.composite_filter.filters.every((filter) => {\n              if (!filter.has_field_filter) {\n                console.error(\"composite_filter only supports field_filter\");\n                throw new Error(\"composite_filter only supports field_filter\");\n              }\n              const field = document.getField(\n                filter.field_filter.field.field_path,\n              );\n              if (!field) return false;\n              return v1FilterDocuments(field, filter.field_filter);\n            });\n          }\n          if (\n            query.where.composite_filter.op ===\n            v1StructuredQueryCompositeFilterOperator.OR\n          ) {\n            return query.where.composite_filter.filters.some((filter) => {\n              if (!filter.has_field_filter) {\n                console.error(\"composite_filter only supports field_filter\");\n                throw new Error(\"composite_filter only supports field_filter\");\n              }\n              const field = document.getField(\n                filter.field_filter.field.field_path,\n              );\n              if (!field) return false;\n              return v1FilterDocuments(field, filter.field_filter);\n            });\n          }\n          // this is unreachable\n          return false;\n        });\n      }\n    }\n\n    if (query.has_limit) {\n      docs = docs.slice(0, query.limit.value);\n    }\n\n    return docs;\n  }\n\n  v1Listen(\n    listen: v1ListenRequest,\n    callback: (response: v1ListenResponse) => void,\n    onEnd: (handler: () => void) => void,\n  ) {\n    if (listen.has_remove_target) {\n      console.error(\"remove_target is not implemented\");\n      throw new Error(\"remove_target is not implemented\");\n    }\n    if (listen.has_add_target) {\n      const sendNewDocuments = (docs: FirestoreStateDocument[]) => {\n        for (const doc of docs) {\n          callback(\n            v1ListenResponse.fromObject({\n              document_change: {\n                document: doc.toV1DocumentObject(),\n                target_ids: [listen.add_target.target_id],\n              },\n            }),\n          );\n        }\n        callback(\n          v1ListenResponse.fromObject({\n            target_change: {\n              read_time: TimestampFromNow().toObject(),\n              target_change_type: v1TargetChangeTargetChangeType.CURRENT,\n              target_ids: [listen.add_target.target_id],\n            },\n          }),\n        );\n        callback(\n          v1ListenResponse.fromObject({\n            target_change: {\n              read_time: TimestampFromNow().toObject(),\n              target_change_type: v1TargetChangeTargetChangeType.NO_CHANGE,\n              target_ids: [],\n            },\n          }),\n        );\n      };\n\n      if (listen.add_target.has_query) {\n        let currentDocumentsPaths: string[] = [];\n        callback(\n          v1ListenResponse.fromObject({\n            target_change: {\n              target_change_type: v1TargetChangeTargetChangeType.ADD,\n              target_ids: [listen.add_target.target_id],\n            },\n          }),\n        );\n\n        const docs = this.v1Query(\n          listen.add_target.query.parent,\n          listen.add_target.query.structured_query,\n        );\n        currentDocumentsPaths = docs.map((v) => v.getPath());\n        sendNewDocuments(docs);\n\n        const handleOnUpdate = async () => {\n          await new Promise((resolve) => setImmediate(resolve));\n          const nextDocuments = this.v1Query(\n            listen.add_target.query.parent,\n            listen.add_target.query.structured_query,\n          );\n          const newDocumentsPaths = nextDocuments.map((v) => v.getPath());\n          const hasCreate = newDocumentsPaths.some(\n            (v) => !currentDocumentsPaths.includes(v),\n          );\n          const hasDelete = currentDocumentsPaths.some(\n            (v) => !newDocumentsPaths.includes(v),\n          );\n          const hasUpdate =\n            !hasCreate &&\n            !hasDelete &&\n            newDocumentsPaths.length === currentDocumentsPaths.length &&\n            newDocumentsPaths.every((v) => currentDocumentsPaths.includes(v)) &&\n            currentDocumentsPaths.every((v) => newDocumentsPaths.includes(v));\n\n          const hasChange = hasDelete || hasCreate || hasUpdate;\n\n          if (!hasChange) {\n            // pass\n            return;\n          }\n          callback(\n            v1ListenResponse.fromObject({\n              target_change: {\n                read_time: TimestampFromNow().toObject(),\n                target_change_type: v1TargetChangeTargetChangeType.RESET,\n                target_ids: [listen.add_target.target_id],\n              },\n            }),\n          );\n          currentDocumentsPaths = nextDocuments.map((v) => v.getPath());\n          sendNewDocuments(nextDocuments);\n        };\n        this.emitter.on(\"create-document\", handleOnUpdate);\n        onEnd(() => this.emitter.off(\"create-document\", handleOnUpdate));\n\n        this.emitter.on(\"update-document\", handleOnUpdate);\n        onEnd(() => this.emitter.off(\"update-document\", handleOnUpdate));\n        this.emitter.on(\"delete-document\", handleOnUpdate);\n        onEnd(() => this.emitter.off(\"delete-document\", handleOnUpdate));\n      } else if (listen.add_target.has_documents) {\n        callback(\n          v1ListenResponse.fromObject({\n            target_change: {\n              target_change_type: v1TargetChangeTargetChangeType.ADD,\n              target_ids: [listen.add_target.target_id],\n            },\n          }),\n        );\n\n        sendNewDocuments(\n          listen.add_target.documents.documents\n            .map((path) => {\n              const document = this.getDocument(path);\n              if (!document.metadata.hasExist) {\n                return null;\n              }\n              return document;\n            })\n            .filter(isNotNull),\n        );\n\n        const handleOnUpdate = async ({\n          document,\n        }: {\n          document: FirestoreStateDocument;\n        }) => {\n          await new Promise((resolve) => setImmediate(resolve));\n          const hasChange = listen.add_target.documents.documents.includes(\n            document.getPath(),\n          );\n          if (!hasChange) {\n            // pass\n            return;\n          }\n          callback(\n            v1ListenResponse.fromObject({\n              target_change: {\n                read_time: TimestampFromNow().toObject(),\n                target_change_type: v1TargetChangeTargetChangeType.RESET,\n                target_ids: [listen.add_target.target_id],\n              },\n            }),\n          );\n          sendNewDocuments(\n            listen.add_target.documents.documents\n              .map((path) => {\n                const document = this.getDocument(path);\n                if (!document.metadata.hasExist) {\n                  return null;\n                }\n                return document;\n              })\n              .filter(isNotNull),\n          );\n        };\n        this.emitter.on(\"create-document\", handleOnUpdate);\n        onEnd(() => this.emitter.off(\"create-document\", handleOnUpdate));\n\n        this.emitter.on(\"update-document\", handleOnUpdate);\n        onEnd(() => this.emitter.off(\"update-document\", handleOnUpdate));\n        this.emitter.on(\"delete-document\", handleOnUpdate);\n        onEnd(() => this.emitter.off(\"delete-document\", handleOnUpdate));\n      }\n    }\n  }\n}\n","import type { Value as v1Value } from \"@firestore-emulator/proto/dist/google/firestore/v1/document\";\nimport { NullValue } from \"@firestore-emulator/proto/dist/google/protobuf/struct\";\n\nexport type ValueObjectType = ReturnType<typeof v1Value.prototype.toObject>;\nexport interface FirestoreStateDocumentBaseField {\n  eq(other: FirestoreStateDocumentFields): boolean;\n  gt(other: FirestoreStateDocumentFields): boolean;\n  gte(other: FirestoreStateDocumentFields): boolean;\n  lt(other: FirestoreStateDocumentFields): boolean;\n  lte(other: FirestoreStateDocumentFields): boolean;\n  toJSON(): { type: string; value: unknown };\n  toV1ValueObject(): ValueObjectType;\n}\n\nexport class FirestoreStateDocumentStringField\n  implements FirestoreStateDocumentBaseField\n{\n  type = \"string_value\" as const;\n  constructor(readonly value: string) {}\n\n  toJSON() {\n    return { type: this.type, value: this.value };\n  }\n\n  toV1ValueObject(): ValueObjectType {\n    return { string_value: this.value };\n  }\n\n  eq(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentStringField &&\n      this.value === other.value\n    );\n  }\n\n  lt(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentStringField &&\n      this.value < other.value\n    );\n  }\n\n  lte(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentStringField &&\n      this.value <= other.value\n    );\n  }\n\n  gt(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentStringField &&\n      this.value > other.value\n    );\n  }\n\n  gte(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentStringField &&\n      this.value >= other.value\n    );\n  }\n}\n\nexport class FirestoreStateDocumentNullField\n  implements FirestoreStateDocumentBaseField\n{\n  type = \"null_value\" as const;\n  value = null;\n  toJSON() {\n    return { type: this.type, value: null } as const;\n  }\n\n  toV1ValueObject(): ValueObjectType {\n    return { null_value: NullValue.NULL_VALUE };\n  }\n\n  eq(other: FirestoreStateDocumentFields): boolean {\n    return other.type === this.type;\n  }\n\n  lt(_other: FirestoreStateDocumentFields): boolean {\n    return false;\n  }\n\n  lte(_other: FirestoreStateDocumentFields): boolean {\n    return false;\n  }\n\n  gt(_other: FirestoreStateDocumentFields): boolean {\n    return false;\n  }\n\n  gte(_other: FirestoreStateDocumentFields): boolean {\n    return false;\n  }\n}\n\nexport class FirestoreStateDocumentBooleanField\n  implements FirestoreStateDocumentBaseField\n{\n  type = \"boolean_value\" as const;\n  constructor(readonly value: boolean) {}\n\n  toJSON() {\n    return { type: this.type, value: this.value };\n  }\n\n  toV1ValueObject(): ValueObjectType {\n    return { boolean_value: this.value };\n  }\n\n  eq(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentBooleanField &&\n      this.value === other.value\n    );\n  }\n\n  lt(_other: FirestoreStateDocumentFields): boolean {\n    return false;\n  }\n\n  lte(_other: FirestoreStateDocumentFields): boolean {\n    return false;\n  }\n\n  gt(_other: FirestoreStateDocumentFields): boolean {\n    return false;\n  }\n\n  gte(_other: FirestoreStateDocumentFields): boolean {\n    return false;\n  }\n}\n\nexport class FirestoreStateDocumentIntegerField\n  implements FirestoreStateDocumentBaseField\n{\n  type = \"integer_value\" as const;\n  constructor(readonly value: number) {\n    if (!Number.isInteger(value)) {\n      throw new Error(`value must be integer. value=${value}`);\n    }\n  }\n\n  toJSON() {\n    return { type: this.type, value: this.value };\n  }\n\n  toV1ValueObject(): ValueObjectType {\n    return { integer_value: this.value };\n  }\n\n  eq(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentIntegerField &&\n      this.value === other.value\n    );\n  }\n\n  lt(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentIntegerField &&\n      this.value < other.value\n    );\n  }\n\n  lte(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentIntegerField &&\n      this.value <= other.value\n    );\n  }\n\n  gt(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentIntegerField &&\n      this.value > other.value\n    );\n  }\n\n  gte(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentIntegerField &&\n      this.value >= other.value\n    );\n  }\n\n  add(\n    other: FirestoreStateDocumentIntegerField,\n  ): FirestoreStateDocumentIntegerField;\n  add(\n    other: FirestoreStateDocumentDoubleField,\n  ): FirestoreStateDocumentDoubleField;\n  add(\n    other:\n      | FirestoreStateDocumentIntegerField\n      | FirestoreStateDocumentDoubleField,\n  ): FirestoreStateDocumentIntegerField | FirestoreStateDocumentDoubleField {\n    if (other instanceof FirestoreStateDocumentIntegerField) {\n      return new FirestoreStateDocumentIntegerField(this.value + other.value);\n    }\n    if (other instanceof FirestoreStateDocumentDoubleField) {\n      return new FirestoreStateDocumentDoubleField(this.value + other.value);\n    }\n    throw new Error(`unsupported type. other=${other}`);\n  }\n}\n\nexport class FirestoreStateDocumentDoubleField\n  implements FirestoreStateDocumentBaseField\n{\n  type = \"double_value\" as const;\n  constructor(readonly value: number) {}\n\n  toJSON() {\n    return { type: this.type, value: this.value };\n  }\n\n  toV1ValueObject(): ValueObjectType {\n    return { double_value: this.value };\n  }\n\n  eq(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentDoubleField &&\n      this.value === other.value\n    );\n  }\n\n  lt(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentDoubleField &&\n      this.value < other.value\n    );\n  }\n\n  lte(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentDoubleField &&\n      this.value <= other.value\n    );\n  }\n\n  gt(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentDoubleField &&\n      this.value > other.value\n    );\n  }\n\n  gte(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentDoubleField &&\n      this.value >= other.value\n    );\n  }\n\n  add(\n    other:\n      | FirestoreStateDocumentIntegerField\n      | FirestoreStateDocumentDoubleField,\n  ): FirestoreStateDocumentDoubleField {\n    if (other instanceof FirestoreStateDocumentIntegerField) {\n      return new FirestoreStateDocumentDoubleField(this.value + other.value);\n    }\n    if (other instanceof FirestoreStateDocumentDoubleField) {\n      return new FirestoreStateDocumentDoubleField(this.value + other.value);\n    }\n    throw new Error(`unsupported type. other=${other}`);\n  }\n}\n\nexport class FirestoreStateDocumentTimestampField\n  implements FirestoreStateDocumentBaseField\n{\n  type = \"timestamp_value\" as const;\n  constructor(readonly value: { nanos: number; seconds: number }) {}\n\n  static fromDate(date: Date) {\n    return new FirestoreStateDocumentTimestampField({\n      nanos: (date.getTime() % 1000) * 1000000,\n      seconds: Math.floor(date.getTime() / 1000),\n    });\n  }\n\n  toJSON() {\n    return { type: this.type, value: this.value } as const;\n  }\n\n  toV1ValueObject(): ValueObjectType {\n    return { timestamp_value: this.value };\n  }\n\n  eq(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentTimestampField &&\n      this.value.seconds === other.value.seconds &&\n      this.value.nanos === other.value.nanos\n    );\n  }\n\n  lt(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentTimestampField &&\n      (this.value.seconds < other.value.seconds ||\n        (this.value.seconds === other.value.seconds &&\n          this.value.nanos < other.value.nanos))\n    );\n  }\n\n  lte(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentTimestampField &&\n      (this.value.seconds < other.value.seconds ||\n        (this.value.seconds === other.value.seconds &&\n          this.value.nanos <= other.value.nanos))\n    );\n  }\n\n  gt(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentTimestampField &&\n      (this.value.seconds > other.value.seconds ||\n        (this.value.seconds === other.value.seconds &&\n          this.value.nanos > other.value.nanos))\n    );\n  }\n\n  gte(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentTimestampField &&\n      (this.value.seconds > other.value.seconds ||\n        (this.value.seconds === other.value.seconds &&\n          this.value.nanos >= other.value.nanos))\n    );\n  }\n}\n\nexport class FirestoreStateDocumentBytesField\n  implements FirestoreStateDocumentBaseField\n{\n  type = \"bytes_value\" as const;\n  constructor(readonly value: Uint8Array) {}\n\n  toJSON() {\n    return { type: this.type, value: this.value } as const;\n  }\n\n  toV1ValueObject(): ValueObjectType {\n    return { bytes_value: this.value };\n  }\n\n  eq(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentBytesField &&\n      this.value.toString() === other.value.toString()\n    );\n  }\n\n  lt(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentBytesField &&\n      this.value.toString() < other.value.toString()\n    );\n  }\n\n  lte(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentBytesField &&\n      this.value.toString() <= other.value.toString()\n    );\n  }\n\n  gt(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentBytesField &&\n      this.value.toString() > other.value.toString()\n    );\n  }\n\n  gte(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentBytesField &&\n      this.value.toString() >= other.value.toString()\n    );\n  }\n}\n\nexport class FirestoreStateDocumentReferenceField\n  implements FirestoreStateDocumentBaseField\n{\n  type = \"reference_value\" as const;\n  constructor(readonly value: string) {}\n\n  toJSON() {\n    return { type: this.type, value: this.value };\n  }\n\n  toV1ValueObject(): ValueObjectType {\n    return { reference_value: this.value };\n  }\n\n  eq(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentReferenceField &&\n      this.value === other.value\n    );\n  }\n\n  lt(_other: FirestoreStateDocumentFields): boolean {\n    return false;\n  }\n\n  lte(_other: FirestoreStateDocumentFields): boolean {\n    return false;\n  }\n\n  gt(_other: FirestoreStateDocumentFields): boolean {\n    return false;\n  }\n\n  gte(_other: FirestoreStateDocumentFields): boolean {\n    return false;\n  }\n}\n\nexport class FirestoreStateDocumentGeoPointField\n  implements FirestoreStateDocumentBaseField\n{\n  type = \"geo_point_value\" as const;\n  constructor(readonly value: { latitude: number; longitude: number }) {}\n\n  toJSON() {\n    return { type: this.type, value: this.value };\n  }\n\n  toV1ValueObject(): ValueObjectType {\n    return { geo_point_value: this.value };\n  }\n\n  eq(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentGeoPointField &&\n      this.value.latitude === other.value.latitude &&\n      this.value.longitude === other.value.longitude\n    );\n  }\n\n  lt(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentGeoPointField &&\n      (this.value.latitude < other.value.latitude ||\n        this.value.longitude < other.value.longitude)\n    );\n  }\n\n  lte(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentGeoPointField &&\n      (this.value.latitude <= other.value.latitude ||\n        this.value.longitude <= other.value.longitude)\n    );\n  }\n\n  gt(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentGeoPointField &&\n      (this.value.latitude > other.value.latitude ||\n        this.value.longitude > other.value.longitude)\n    );\n  }\n\n  gte(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentGeoPointField &&\n      (this.value.latitude >= other.value.latitude ||\n        this.value.longitude >= other.value.longitude)\n    );\n  }\n}\n\nexport class FirestoreStateDocumentArrayField\n  implements FirestoreStateDocumentBaseField\n{\n  type = \"array_value\" as const;\n  constructor(readonly value: FirestoreStateDocumentFields[]) {}\n\n  toJSON(): { type: string; value: unknown } {\n    return {\n      type: this.type,\n      value: this.value.map((v) => v.toJSON()),\n    };\n  }\n\n  toV1ValueObject(): ValueObjectType {\n    return {\n      array_value: { values: this.value.map((v) => v.toV1ValueObject()) },\n    };\n  }\n\n  eq(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentArrayField &&\n      this.value.length === other.value.length &&\n      this.value.every((v, i) => {\n        const item = other.value[i];\n        if (!item) return false;\n        return item.eq(v);\n      })\n    );\n  }\n\n  lt(_other: FirestoreStateDocumentFields): boolean {\n    return false;\n  }\n\n  lte(_other: FirestoreStateDocumentFields): boolean {\n    return false;\n  }\n\n  gt(_other: FirestoreStateDocumentFields): boolean {\n    return false;\n  }\n\n  gte(_other: FirestoreStateDocumentFields): boolean {\n    return false;\n  }\n}\n\nexport class FirestoreStateDocumentMapField\n  implements FirestoreStateDocumentBaseField\n{\n  type = \"map_value\" as const;\n  constructor(readonly value: Record<string, FirestoreStateDocumentFields>) {}\n\n  toJSON(): { type: string; value: unknown } {\n    return {\n      type: this.type,\n      value: Object.fromEntries(\n        Object.entries(this.value).map(([k, v]) => [k, v.toJSON()]),\n      ),\n    };\n  }\n\n  toV1ValueObject(): ValueObjectType {\n    return {\n      map_value: {\n        fields: Object.fromEntries(\n          Object.entries(this.value).map(([k, v]) => [k, v.toV1ValueObject()]),\n        ),\n      },\n    };\n  }\n\n  eq(other: FirestoreStateDocumentFields): boolean {\n    return (\n      other instanceof FirestoreStateDocumentMapField &&\n      Object.keys(this.value).length === Object.keys(other.value).length &&\n      Object.entries(this.value).every(([k, v]) => {\n        const item = other.value[k];\n        if (!item) return false;\n        return item.eq(v);\n      })\n    );\n  }\n\n  lt(_other: FirestoreStateDocumentFields): boolean {\n    return false;\n  }\n\n  lte(_other: FirestoreStateDocumentFields): boolean {\n    return false;\n  }\n\n  gt(_other: FirestoreStateDocumentFields): boolean {\n    return false;\n  }\n\n  gte(_other: FirestoreStateDocumentFields): boolean {\n    return false;\n  }\n}\n\nexport type FirestoreStateDocumentFields =\n  | FirestoreStateDocumentStringField\n  | FirestoreStateDocumentNullField\n  | FirestoreStateDocumentBooleanField\n  | FirestoreStateDocumentIntegerField\n  | FirestoreStateDocumentDoubleField\n  | FirestoreStateDocumentTimestampField\n  | FirestoreStateDocumentBytesField\n  | FirestoreStateDocumentReferenceField\n  | FirestoreStateDocumentGeoPointField\n  | FirestoreStateDocumentArrayField\n  | FirestoreStateDocumentMapField;\n\nexport const convertV1DocumentField = (\n  field: v1Value,\n): FirestoreStateDocumentFields => {\n  if (field.has_string_value)\n    return new FirestoreStateDocumentStringField(field.string_value);\n  if (field.has_null_value) return new FirestoreStateDocumentNullField();\n  if (field.has_boolean_value)\n    return new FirestoreStateDocumentBooleanField(field.boolean_value);\n  if (field.has_integer_value)\n    return new FirestoreStateDocumentIntegerField(field.integer_value);\n  if (field.has_double_value)\n    return new FirestoreStateDocumentDoubleField(field.double_value);\n  if (field.has_timestamp_value)\n    return new FirestoreStateDocumentTimestampField({\n      nanos: field.timestamp_value.nanos,\n      seconds: field.timestamp_value.seconds,\n    });\n  if (field.has_bytes_value)\n    return new FirestoreStateDocumentBytesField(field.bytes_value);\n  if (field.has_reference_value)\n    return new FirestoreStateDocumentReferenceField(field.reference_value);\n  if (field.has_geo_point_value)\n    return new FirestoreStateDocumentGeoPointField({\n      latitude: field.geo_point_value.latitude,\n      longitude: field.geo_point_value.longitude,\n    });\n  if (field.has_array_value)\n    return new FirestoreStateDocumentArrayField(\n      field.array_value.values.map(convertV1DocumentField),\n    );\n  if (field.has_map_value)\n    return new FirestoreStateDocumentMapField(\n      Object.fromEntries(\n        Array.from(field.map_value.fields.entries()).map(([k, v]) => [\n          k,\n          convertV1DocumentField(v),\n        ]),\n      ),\n    );\n  throw new Error(`unknown field type. field=${JSON.stringify(field)}`);\n};\n\nexport const convertV1Value = (\n  value: v1Value,\n): ReturnType<typeof v1Value.prototype.toObject> => {\n  return convertV1DocumentField(value).toV1ValueObject();\n};\n","import { produce } from \"immer\";\n\nimport {\n  type FirestoreStateDocumentFields,\n  FirestoreStateDocumentMapField,\n} from \"./field\";\n\n/**\n * If the key contains a \".\", it will be wrapped with \"\\`\" characters.\n * For example, if the key is `user.name`, it will be transformed into `` `user.name` ``.\n */\nfunction escapeKey(key: string): string {\n  return key.includes(\".\") ? `\\`${key}\\`` : key;\n}\n\nfunction getNestedUpdateMask(updateMask: string[], key: string): string[] {\n  const escapedKey = escapeKey(key);\n  return updateMask\n    .filter((m) => m.startsWith(`${escapedKey}.`))\n    .map((m) => m.substring(escapedKey.length + 1));\n}\n\nfunction isUpdatable(updateMask: string[], key: string): boolean {\n  return updateMask.length === 0 || updateMask.includes(escapeKey(key));\n}\n\nexport function updateFields(\n  current: Record<string, FirestoreStateDocumentFields>,\n  fields: Record<string, FirestoreStateDocumentFields>,\n  updateMask: string[],\n): Record<string, FirestoreStateDocumentFields> {\n  return produce(current, (draft) => {\n    for (const [key, field] of Object.entries(fields)) {\n      const updatable = isUpdatable(updateMask, key);\n      const nestedUpdateMask = getNestedUpdateMask(updateMask, key);\n      if (updatable) {\n        draft[key] = field;\n      } else if (\n        field.type === \"map_value\" &&\n        (draft[key] == null || draft[key].type === \"map_value\")\n      ) {\n        draft[key] = new FirestoreStateDocumentMapField(\n          updateFields(draft[key]?.value ?? {}, field.value, nestedUpdateMask),\n        );\n      }\n    }\n  });\n}\n"],"mappings":"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","names":["produce"]}