@twin.org/entity-storage-connector-gcp-firestore 0.0.3-next.21 → 0.0.3-next.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -704,9 +704,9 @@ export class FirestoreEntityStorageConnector {
704
704
  /**
705
705
  * Returns true when the condition tree is guaranteed to match nothing due to empty
706
706
  * In lists, respecting AND/OR boolean semantics (#141):
707
- * - AND group: true if ANY child is always-false (false AND x = false)
708
- * - OR group: true if ALL children are always-false (false OR false = false)
709
- * - Leaf: true only for `In []`
707
+ * - AND group: true if ANY child is always-false (false AND x = false)
708
+ * - OR group: true if ALL children are always-false (false OR false = false)
709
+ * - Leaf: true only for `In []`
710
710
  * @param condition The condition tree to inspect.
711
711
  * @returns True if a short-circuit to empty results is required.
712
712
  * @internal
@@ -804,6 +804,7 @@ export class FirestoreEntityStorageConnector {
804
804
  * Only called for native conditions (needsPostFilter must be false).
805
805
  * @param condition The condition to convert.
806
806
  * @returns A Firestore Filter.
807
+ * @throws GeneralError if the comparison operator is not supported.
807
808
  * @internal
808
809
  */
809
810
  buildFilter(condition) {
@@ -843,6 +844,7 @@ export class FirestoreEntityStorageConnector {
843
844
  }
844
845
  /**
845
846
  * Get the collection name based on partition key.
847
+ * @param partitionKey The optional partition key to include in the collection name.
846
848
  * @returns The collection name.
847
849
  * @internal
848
850
  */
@@ -1 +1 @@
1
- {"version":3,"file":"firestoreEntityStorageConnector.js","sourceRoot":"","sources":["../../src/firestoreEntityStorageConnector.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAEN,MAAM,EACN,SAAS,EAGT,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,cAAc,EAAoB,MAAM,mBAAmB,CAAC;AACtF,OAAO,EACN,SAAS,EACT,gBAAgB,EAChB,SAAS,EACT,YAAY,EACZ,MAAM,EACN,YAAY,EAEZ,EAAE,EACF,YAAY,EACZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACN,kBAAkB,EAElB,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,EAGlB,eAAe,EACf,aAAa,EACb,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACN,mBAAmB,EAInB,MAAM,iCAAiC,CAAC;AAOzC;;GAEG;AACH,MAAM,OAAO,+BAA+B;IAG3C;;OAEG;IACI,MAAM,CAAU,UAAU,qCAAqD;IAEtF;;;OAGG;IACK,MAAM,CAAU,cAAc,GAAW,EAAE,CAAC;IAEpD;;;;OAIG;IACK,MAAM,CAAU,oBAAoB,GAAW,GAAG,CAAC;IAE3D;;;OAGG;IACc,iBAAiB,CAAS;IAE3C;;;OAGG;IACc,aAAa,CAAmB;IAEjD;;;OAGG;IACc,oBAAoB,CAAY;IAEjD;;;OAGG;IACc,WAAW,CAA2B;IAEvD;;;OAGG;IACc,OAAO,CAAyC;IAEjE;;;OAGG;IACc,gBAAgB,CAAY;IAE7C;;;OAGG;IACH,YAAY,OAA2D;QACtE,MAAM,CAAC,MAAM,CAAC,+BAA+B,CAAC,UAAU,aAAmB,OAAO,CAAC,CAAC;QACpF,MAAM,CAAC,WAAW,CACjB,+BAA+B,CAAC,UAAU,0BAE1C,OAAO,CAAC,YAAY,CACpB,CAAC;QACF,MAAM,CAAC,MAAM,CACZ,+BAA+B,CAAC,UAAU,oBAE1C,OAAO,CAAC,MAAM,CACd,CAAC;QACF,MAAM,CAAC,WAAW,CACjB,+BAA+B,CAAC,UAAU,8BAE1C,OAAO,CAAC,MAAM,CAAC,SAAS,CACxB,CAAC;QACF,MAAM,CAAC,WAAW,CACjB,+BAA+B,CAAC,UAAU,mCAE1C,OAAO,CAAC,MAAM,CAAC,cAAc,CAC7B,CAAC;QAEF,IAAI,WAAiC,CAAC;QACtC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC;YAC3C,MAAM,CAAC,YAAY,CAClB,+BAA+B,CAAC,UAAU,gCAE1C,OAAO,CAAC,MAAM,CAAC,WAAW,CAC1B,CAAC;YACF,WAAW,GAAG,YAAY,CAAC,SAAS,CACnC,SAAS,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CACnD,CAAC;QACH,CAAC;QAED,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;QAC9B,IAAI,CAAC,iBAAiB,GAAG,OAAO,CAAC,YAAY,CAAC;QAC9C,IAAI,CAAC,aAAa,GAAG,mBAAmB,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QACnE,IAAI,CAAC,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,CAAC;QACxD,IAAI,CAAC,WAAW,GAAG,kBAAkB,CAAC,aAAa,CAAI,IAAI,CAAC,aAAa,CAAC,CAAC;QAE3E,MAAM,gBAAgB,GAAa;YAClC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS;YACjC,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU;YACnC,cAAc,EAAE,IAAI,CAAC,OAAO,CAAC,cAAc;YAC3C,eAAe,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,eAAe;YACvD,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO;YACvC,WAAW;SACX,CAAC;QAEF,IAAI,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC3C,gBAAgB,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;YAC9C,gBAAgB,CAAC,GAAG,GAAG,KAAK,CAAC;QAC9B,CAAC;QAED,IAAI,CAAC,gBAAgB,GAAG,IAAI,SAAS,CAAC,gBAAgB,CAAC,CAAC;IACzD,CAAC;IAED;;;OAGG;IACI,SAAS;QACf,OAAO,+BAA+B,CAAC,UAAU,CAAC;IACnD,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,MAAM;QAClB,IAAI,CAAC;YACJ,MAAM,IAAI,CAAC,gBAAgB,CAAC,eAAe,EAAE,CAAC;YAC9C,OAAO;gBACN;oBACC,MAAM,EAAE,+BAA+B,CAAC,UAAU;oBAClD,MAAM,EAAE,YAAY,CAAC,EAAE;oBACvB,WAAW,EAAE,mBAAmB;oBAChC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,cAAc,EAAE,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE;iBACxF;aACD,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACR,OAAO;gBACN;oBACC,MAAM,EAAE,+BAA+B,CAAC,UAAU;oBAClD,MAAM,EAAE,YAAY,CAAC,KAAK;oBAC1B,WAAW,EAAE,mBAAmB;oBAChC,OAAO,EAAE,kBAAkB;oBAC3B,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,cAAc,EAAE,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE;iBACxF;aACD,CAAC;QACH,CAAC;IACF,CAAC;IAED;;;OAGG;IACI,SAAS;QACf,OAAO,IAAI,CAAC,aAA8B,CAAC;IAC5C,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,SAAS,CAAC,wBAAiC;QACvD,MAAM,WAAW,GAAG,gBAAgB,CAAC,WAAW,CAAoB,wBAAwB,CAAC,CAAC;QAE9F,IAAI,CAAC;YACJ,MAAM,WAAW,EAAE,GAAG,CAAC;gBACtB,KAAK,EAAE,MAAM;gBACb,MAAM,EAAE,+BAA+B,CAAC,UAAU;gBAClD,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;gBACd,OAAO,EAAE,mBAAmB;gBAC5B,IAAI,EAAE;oBACL,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS;oBACjC,cAAc,EAAE,IAAI,CAAC,OAAO,CAAC,cAAc;iBAC3C;aACD,CAAC,CAAC;YAEH,yDAAyD;YACzD,yDAAyD;YACzD,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC1F,MAAM,OAAO,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAClC,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC;YAEvB,MAAM,WAAW,EAAE,GAAG,CAAC;gBACtB,KAAK,EAAE,MAAM;gBACb,MAAM,EAAE,+BAA+B,CAAC,UAAU;gBAClD,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;gBACd,OAAO,EAAE,kBAAkB;gBAC3B,IAAI,EAAE;oBACL,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS;oBACjC,cAAc,EAAE,IAAI,CAAC,OAAO,CAAC,cAAc;iBAC3C;aACD,CAAC,CAAC;YAEH,OAAO,IAAI,CAAC;QACb,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,WAAW,EAAE,GAAG,CAAC;gBACtB,KAAK,EAAE,OAAO;gBACd,MAAM,EAAE,+BAA+B,CAAC,UAAU;gBAClD,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;gBACd,OAAO,EAAE,yBAAyB;gBAClC,KAAK,EAAE,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC;gBAC/B,IAAI,EAAE;oBACL,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS;oBACjC,cAAc,EAAE,IAAI,CAAC,OAAO,CAAC,cAAc;iBAC3C;aACD,CAAC,CAAC;YACH,OAAO,KAAK,CAAC;QACd,CAAC;IACF,CAAC;IAED;;;;;;OAMG;IACI,KAAK,CAAC,GAAG,CACf,EAAU,EACV,cAAwB,EACxB,UAAoD;QAEpD,MAAM,CAAC,WAAW,CAAC,+BAA+B,CAAC,UAAU,QAAc,EAAE,CAAC,CAAC;QAE/E,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;QACxD,MAAM,YAAY,GAAG,eAAe,CAAC,kBAAkB,CACtD,UAAU,EACV,IAAI,CAAC,oBAAoB,EACzB,+BAA+B,CAAC,oBAAoB,CACpD,CAAC;QAEF,IAAI,CAAC;YACJ,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC;YAEvF,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;gBAChC,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAClC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,GAAG,EAAE,CAAC;gBAE/B,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;oBAChB,OAAO,mBAAmB,CAAC,eAAe,CAAI,GAAG,CAAC,IAAI,EAAO,EAAE,EAAE,CAAC,CAAC;gBACpE,CAAC;YACF,CAAC;YAED,sCAAsC;YACtC,IAAI,KAAK,GAAU,UAAU,CAAC;YAE9B,IAAI,cAAc,EAAE,CAAC;gBACpB,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,cAAwB,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;YACzD,CAAC;iBAAM,CAAC;gBACP,0DAA0D;gBAC1D,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,QAAkB,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;YACpE,CAAC;YAED,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC/B,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;oBACpC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,QAAkB,EAAE,IAAI,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC;gBAC1E,CAAC;YACF,CAAC;YAED,MAAM,aAAa,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;YACjD,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;gBAC1B,OAAO,mBAAmB,CAAC,eAAe,CAAI,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAO,EAAE,EAAE,CAAC,CAAC;YACtF,CAAC;QACF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,IAAI,YAAY,CACrB,+BAA+B,CAAC,UAAU,EAC1C,iBAAiB,EACjB,EAAE,EAAE,EAAE,EACN,GAAG,CACH,CAAC;QACH,CAAC;IACF,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,GAAG,CAAC,MAAS,EAAE,UAAoD;QAC/E,MAAM,CAAC,MAAM,CAAC,+BAA+B,CAAC,UAAU,YAAkB,MAAM,CAAC,CAAC;QAElF,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;QACxD,MAAM,YAAY,GAAG,eAAe,CAAC,kBAAkB,CACtD,UAAU,EACV,IAAI,CAAC,oBAAoB,EACzB,+BAA+B,CAAC,oBAAoB,CACpD,CAAC;QAEF,MAAM,QAAQ,GAAG,mBAAmB,CAAC,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,SAAS,EAAE;YACzF,YAAY,EAAE,SAAS;SACvB,CAAC,CAAC;QAEH,IAAI,CAAC;YACJ,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAW,CAAC;YAEzD,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC;YAEvF,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAElC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;gBAChC,MAAM,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC5B,CAAC;iBAAM,CAAC;gBACP,MAAM,IAAI,CAAC,gBAAgB,CAAC,cAAc,CAAC,KAAK,EAAC,WAAW,EAAC,EAAE;oBAC9D,MAAM,WAAW,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;oBAElD,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;wBACzB,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,QAAkB,CAAC,CAAC;oBAC7C,CAAC;yBAAM,CAAC;wBACP,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,EAAO,CAAC;wBAErC,IACC,gBAAgB,CAAC,KAAK,CAAC,IAAI,EAAE;4BAC5B,UAAU,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gCAChC,QAAQ,EAAE,CAAC,CAAC,QAAkB;gCAC9B,UAAU,EAAE,kBAAkB,CAAC,MAAM;gCACrC,KAAK,EAAE,CAAC,CAAC,KAAK;6BACd,CAAC,CAAC;yBACH,CAAC,EACD,CAAC;4BACF,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,QAAkB,CAAC,CAAC;wBAC7C,CAAC;oBACF,CAAC;gBACF,CAAC,CAAC,CAAC;YACJ,CAAC;QACF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,IAAI,YAAY,CACrB,+BAA+B,CAAC,UAAU,EAC1C,iBAAiB,EACjB,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,EACjB,GAAG,CACH,CAAC;QACH,CAAC;IACF,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,QAAQ,CAAC,QAAa;QAClC,MAAM,CAAC,UAAU,CAAC,+BAA+B,CAAC,UAAU,cAAoB,QAAQ,CAAC,CAAC;QAE1F,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;QACxD,MAAM,YAAY,GAAG,eAAe,CAAC,kBAAkB,CACtD,UAAU,EACV,IAAI,CAAC,oBAAoB,EACzB,+BAA+B,CAAC,oBAAoB,CACpD,CAAC;QAEF,MAAM,gBAAgB,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAC9C,mBAAmB,CAAC,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,SAAS,EAAE;YACxE,YAAY,EAAE,SAAS;SACvB,CAAC,CACF,CAAC;QAEF,IAAI,CAAC;YACJ,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC;YACvF,MAAM,SAAS,GAAG,+BAA+B,CAAC,cAAc,CAAC;YACjE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,gBAAgB,CAAC,MAAM,EAAE,CAAC,IAAI,SAAS,EAAE,CAAC;gBAC7D,MAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC;gBACvD,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,CAAC;gBAC5C,KAAK,MAAM,MAAM,IAAI,KAAK,EAAE,CAAC;oBAC5B,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAW,CAAC;oBACvD,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;oBAClC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,MAAoC,CAAC,CAAC;gBACzD,CAAC;gBACD,MAAM,KAAK,CAAC,MAAM,EAAE,CAAC;YACtB,CAAC;QACF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,IAAI,YAAY,CACrB,+BAA+B,CAAC,UAAU,EAC1C,gBAAgB,EAChB,SAAS,EACT,GAAG,CACH,CAAC;QACH,CAAC;IACF,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,KAAK;QACjB,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;QACxD,MAAM,YAAY,GAAG,eAAe,CAAC,kBAAkB,CACtD,UAAU,EACV,IAAI,CAAC,oBAAoB,EACzB,+BAA+B,CAAC,oBAAoB,CACpD,CAAC;QAEF,IAAI,CAAC;YACJ,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC;YACvF,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,GAAG,EAAE,CAAC;YACxC,MAAM,SAAS,GAAG,GAAG,CAAC;YACtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,SAAS,EAAE,CAAC;gBAC1D,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC;gBACpD,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,CAAC;gBAC5C,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;oBACzB,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACvB,CAAC;gBACD,MAAM,KAAK,CAAC,MAAM,EAAE,CAAC;YACtB,CAAC;QACF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,IAAI,YAAY,CACrB,+BAA+B,CAAC,UAAU,EAC1C,aAAa,EACb,SAAS,EACT,GAAG,CACH,CAAC;QACH,CAAC;IACF,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,MAAM,CAClB,EAAU,EACV,UAAoD;QAEpD,MAAM,CAAC,WAAW,CAAC,+BAA+B,CAAC,UAAU,QAAc,EAAE,CAAC,CAAC;QAE/E,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;QACxD,MAAM,YAAY,GAAG,eAAe,CAAC,kBAAkB,CACtD,UAAU,EACV,IAAI,CAAC,oBAAoB,EACzB,+BAA+B,CAAC,oBAAoB,CACpD,CAAC;QAEF,IAAI,CAAC;YACJ,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC;YACvF,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAElC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;gBAChC,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;YACvB,CAAC;iBAAM,CAAC;gBACP,MAAM,IAAI,CAAC,gBAAgB,CAAC,cAAc,CAAC,KAAK,EAAC,WAAW,EAAC,EAAE;oBAC9D,MAAM,WAAW,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;oBAElD,IAAI,WAAW,CAAC,MAAM,EAAE,CAAC;wBACxB,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,EAAO,CAAC;wBACrC,IACC,gBAAgB,CAAC,KAAK,CAAC,IAAI,EAAE;4BAC5B,UAAU,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gCAChC,QAAQ,EAAE,CAAC,CAAC,QAAkB;gCAC9B,UAAU,EAAE,kBAAkB,CAAC,MAAM;gCACrC,KAAK,EAAE,CAAC,CAAC,KAAK;6BACd,CAAC,CAAC;yBACH,CAAC,EACD,CAAC;4BACF,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;wBAC5B,CAAC;oBACF,CAAC;gBACF,CAAC,CAAC,CAAC;YACJ,CAAC;QACF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,IAAI,YAAY,CACrB,+BAA+B,CAAC,UAAU,EAC1C,oBAAoB,EACpB,EAAE,EAAE,EAAE,EACN,GAAG,CACH,CAAC;QACH,CAAC;IACF,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,WAAW,CAAC,GAAa;QACrC,MAAM,CAAC,UAAU,CAAC,+BAA+B,CAAC,UAAU,SAAe,GAAG,CAAC,CAAC;QAEhF,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;QACxD,MAAM,YAAY,GAAG,eAAe,CAAC,kBAAkB,CACtD,UAAU,EACV,IAAI,CAAC,oBAAoB,EACzB,+BAA+B,CAAC,oBAAoB,CACpD,CAAC;QAEF,IAAI,CAAC;YACJ,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC;YACvF,MAAM,SAAS,GAAG,GAAG,CAAC;YACtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,SAAS,EAAE,CAAC;gBAChD,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC;gBAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,CAAC;gBAC5C,KAAK,MAAM,EAAE,IAAI,KAAK,EAAE,CAAC;oBACxB,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;oBAClC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBACtB,CAAC;gBACD,MAAM,KAAK,CAAC,MAAM,EAAE,CAAC;YACtB,CAAC;QACF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,IAAI,YAAY,CACrB,+BAA+B,CAAC,UAAU,EAC1C,mBAAmB,EACnB,SAAS,EACT,GAAG,CACH,CAAC;QACH,CAAC;IACF,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,QAAQ,CAAC,wBAAiC;QACtD,MAAM,WAAW,GAAG,gBAAgB,CAAC,WAAW,CAAoB,wBAAwB,CAAC,CAAC;QAE9F,MAAM,WAAW,EAAE,GAAG,CAAC;YACtB,KAAK,EAAE,MAAM;YACb,MAAM,EAAE,+BAA+B,CAAC,UAAU;YAClD,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;YACd,OAAO,EAAE,kBAAkB;SAC3B,CAAC,CAAC;QAEH,IAAI,CAAC;YACJ,MAAM,IAAI,CAAC,6BAA6B,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;YAEtE,MAAM,WAAW,EAAE,GAAG,CAAC;gBACtB,KAAK,EAAE,MAAM;gBACb,MAAM,EAAE,+BAA+B,CAAC,UAAU;gBAClD,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;gBACd,OAAO,EAAE,eAAe;aACxB,CAAC,CAAC;YAEH,OAAO,IAAI,CAAC;QACb,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,WAAW,EAAE,GAAG,CAAC;gBACtB,KAAK,EAAE,OAAO;gBACd,MAAM,EAAE,+BAA+B,CAAC,UAAU;gBAClD,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;gBACd,OAAO,EAAE,gBAAgB;gBACzB,KAAK,EAAE,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC;aAC/B,CAAC,CAAC;YACH,OAAO,KAAK,CAAC;QACd,CAAC;IACF,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,sBAAsB;QAClC,MAAM,mBAAmB,GAAG,IAAI,CAAC,oBAAoB,CAAC;QACtD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,mBAAmB,CAAC,EAAE,CAAC;YACzC,OAAO,EAAE,CAAC;QACX,CAAC;QACD,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,GAAG,CAAC;YACjD,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,eAAe,EAAE,CAAC;YAClE,MAAM,MAAM,GAAkB,EAAE,CAAC;YACjC,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;gBAC/B,IAAI,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC/B,MAAM,YAAY,GAAG,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;oBACjD,IAAI,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,CAAC;wBAClC,MAAM,CAAC,IAAI,CACV,eAAe,CAAC,UAAU,CACzB,mBAAmB,EACnB,YAAY,EACZ,+BAA+B,CAAC,oBAAoB,CACpD,CACD,CAAC;oBACH,CAAC;gBACF,CAAC;YACF,CAAC;YACD,OAAO,MAAM,CAAC;QACf,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,IAAI,YAAY,CACrB,+BAA+B,CAAC,UAAU,EAC1C,8BAA8B,EAC9B,SAAS,EACT,GAAG,CACH,CAAC;QACH,CAAC;IACF,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,qBAAqB,CACjC,eAAuB;QAEvB,MAAM,uBAAuB,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,YAAY,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QACvF,OAAO,IAAI,+BAA+B,CAAI;YAC7C,YAAY,EAAE,eAAe;YAC7B,MAAM,EAAE,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE;YACpE,mBAAmB,EAAE,IAAI,CAAC,oBAAoB;SAC9C,CAAC,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACI,KAAK,CAAC,iBAAiB,CAC7B,eAAmD,EACnD,OAAiC,EACjC,oBAA6B;QAE7B,qFAAqF;QACrF,wFAAwF;QACxF,yBAAyB;QAEzB,2FAA2F;QAC3F,MAAM,IAAI,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;QAE1C,kFAAkF;QAClF,MAAM,sBAAsB,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC;QAC3D,MAAM,cAAc,GAAG,IAAI,+BAA+B,CAAI;YAC7D,YAAY,EAAE,eAAe,CAAC,iBAAiB;YAC/C,MAAM,EAAE,EAAE,GAAG,eAAe,CAAC,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE;YAC9E,mBAAmB,EAAE,IAAI,CAAC,oBAAoB;SAC9C,CAAC,CAAC;QAEH,IAAI,MAAM,cAAc,CAAC,SAAS,CAAC,oBAAoB,CAAC,EAAE,CAAC;YAC1D,+FAA+F;YAC/F,MAAM,UAAU,GAAG,MAAM,eAAe,CAAC,sBAAsB,EAAE,CAAC;YAClE,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,+BAA+B,CAAC,cAAc,CAAC;YACvF,MAAM,IAAI,CAAC,QAAQ,CAAC,eAAe,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;YAE5E,MAAM,eAAe,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;YAErD,OAAO,cAAc,CAAC;QACvB,CAAC;QACD,MAAM,IAAI,YAAY,CACrB,+BAA+B,CAAC,UAAU,EAC1C,kCAAkC,EAClC,SAAS,CACT,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,gBAAgB,CAC5B,eAAuD,EACvD,OAAiC,EACjC,oBAA6B;QAE7B,uEAAuE;QACvE,MAAM,eAAe,EAAE,QAAQ,EAAE,CAAC,oBAAoB,CAAC,CAAC;IACzD,CAAC;IAED;;;;;;;;OAQG;IACI,KAAK,CAAC,KAAK,CACjB,UAA+B,EAC/B,cAAsE,EACtE,UAAwB,EACxB,MAAe,EACf,KAAc;QAWd,MAAM,gBAAgB,GAAa,EAAE,CAAC;QAEtC,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;QACxD,MAAM,YAAY,GAAG,eAAe,CAAC,kBAAkB,CACtD,UAAU,EACV,IAAI,CAAC,oBAAoB,EACzB,+BAA+B,CAAC,oBAAoB,CACpD,CAAC;QAEF,MAAM,UAAU,GAAG,KAAK,IAAI,+BAA+B,CAAC,cAAc,CAAC;QAE3E,IAAI,CAAC;YACJ,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC;YAEvF,+EAA+E;YAC/E,gFAAgF;YAChF,2DAA2D;YAC3D,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC/D,gBAAgB,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;gBAExC,IAAI,SAAS,GAAG,UAAmB,CAAC;gBAEpC,IAAI,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;oBACnC,KAAK,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,IAAI,cAAc,EAAE,CAAC;wBAC1D,SAAS,GAAG,SAAS,CAAC,OAAO,CAC5B,QAAkB,EAClB,aAAa,KAAK,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAC1D,CAAC;oBACH,CAAC;gBACF,CAAC;gBAED,MAAM,WAAW,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,CAAC;gBAC1C,IAAI,WAAW,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAqB,EAAE,EAAE,CAChE,mBAAmB,CAAC,eAAe,CAAI,GAAG,CAAC,IAAI,EAAO,EAAE,EAAE,CAAC,CAC3D,CAAC;gBAEF,WAAW,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAe,EAAE,UAAU,CAAC,CAAC,CAAC;gBAE3F,IAAI,SAAuB,CAAC;gBAC5B,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;oBAC/B,SAAS,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;wBAC/B,MAAM,GAAG,GAAe,EAAE,CAAC;wBAC3B,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;4BAC/B,IAAI,IAAI,IAAK,CAAY,EAAE,CAAC;gCAC3B,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;4BACrB,CAAC;wBACF,CAAC;wBACD,OAAO,GAAG,CAAC;oBACZ,CAAC,CAAC,CAAC;gBACJ,CAAC;qBAAM,CAAC;oBACP,SAAS,GAAG,WAAW,CAAC;gBACzB,CAAC;gBAED,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBACvE,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,UAAU,CAAC,CAAC;gBACxD,MAAM,UAAU,GACf,KAAK,GAAG,UAAU,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;gBAEhF,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;YAC/C,CAAC;YAED,IAAI,IAAI,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC1C,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;YAC5C,CAAC;YAED,sEAAsE;YACtE,mFAAmF;YACnF,gFAAgF;YAChF,iDAAiD;YACjD,MAAM,mBAAmB,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC;gBAChD,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,UAAU,CAAC,IAAI,SAAS,CAAC;gBACxD,CAAC,CAAC,UAAU,CAAC;YAEd,IAAI,KAAK,GAAG,UAAmB,CAAC;YAEhC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,mBAAmB,CAAC,EAAE,CAAC;gBACpC,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,mBAAmB,CAAC,CAAC;gBACzD,gBAAgB,CAAC,IAAI,CAAC,eAAe,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;YACpE,CAAC;YAED,IAAI,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;gBACnC,KAAK,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,IAAI,cAAc,EAAE,CAAC;oBAC1D,KAAK,GAAG,KAAK,CAAC,OAAO,CACpB,QAAkB,EAClB,aAAa,KAAK,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAC1D,CAAC;gBACH,CAAC;gBACD,gBAAgB,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;YAClE,CAAC;YAED,IAAI,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC5B,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC;gBAChE,IAAI,SAAS,EAAE,MAAM,EAAE,CAAC;oBACvB,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;gBACrC,CAAC;gBACD,gBAAgB,CAAC,IAAI,CAAC,WAAW,MAAM,EAAE,CAAC,CAAC;YAC5C,CAAC;YAED,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC;YACpC,gBAAgB,CAAC,IAAI,CAAC,UAAU,UAAU,EAAE,CAAC,CAAC;YAE9C,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC/B,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,GAAI,UAAuB,CAAC,CAAC;gBAClD,gBAAgB,CAAC,IAAI,CAAC,eAAe,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC/D,CAAC;YAED,MAAM,aAAa,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,CAAC;YACxC,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC;YACvD,MAAM,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC;YAC1F,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,GAAqB,EAAE,EAAE,CACzD,mBAAmB,CAAC,eAAe,CAAI,GAAG,CAAC,IAAI,EAAO,EAAE,EAAE,CAAC,CAC3D,CAAC;YAEF,IAAI,UAA8B,CAAC;YACnC,IAAI,OAAO,EAAE,CAAC;gBACb,UAAU,GAAG,UAAU,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;YACzD,CAAC;YAED,OAAO;gBACN,QAAQ;gBACR,MAAM,EAAE,UAAU;aAClB,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,IAAI,YAAY,CACrB,+BAA+B,CAAC,UAAU,EAC1C,aAAa,EACb,EAAE,gBAAgB,EAAE,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EACjD,GAAG,CACH,CAAC;QACH,CAAC;IACF,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,KAAK,CAAC,UAA+B;QACjD,IAAI,CAAC;YACJ,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;YACxD,MAAM,YAAY,GAAG,eAAe,CAAC,kBAAkB,CACtD,UAAU,EACV,IAAI,CAAC,oBAAoB,EACzB,+BAA+B,CAAC,oBAAoB,CACpD,CAAC;YAEF,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC;YAEvF,IAAI,IAAI,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC1C,OAAO,CAAC,CAAC;YACV,CAAC;YAED,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC/D,MAAM,WAAW,GAAG,MAAM,UAAU,CAAC,GAAG,EAAE,CAAC;gBAC3C,MAAM,WAAW,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAqB,EAAE,EAAE,CAClE,mBAAmB,CAAC,eAAe,CAAI,GAAG,CAAC,IAAI,EAAO,EAAE,EAAE,CAAC,CAC3D,CAAC;gBACF,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAe,EAAE,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC;YAC5F,CAAC;YAED,MAAM,mBAAmB,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC;gBAChD,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,UAAU,CAAC,IAAI,SAAS,CAAC;gBACxD,CAAC,CAAC,UAAU,CAAC;YAEd,IAAI,KAAK,GAAG,UAAmB,CAAC;YAChC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,mBAAmB,CAAC,EAAE,CAAC;gBACpC,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,mBAAmB,CAAC,CAAC;YAC1D,CAAC;YAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,CAAC;YAC3C,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;QAC9B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,IAAI,YAAY,CACrB,+BAA+B,CAAC,UAAU,EAC1C,aAAa,EACb,SAAS,EACT,GAAG,CACH,CAAC;QACH,CAAC;IACF,CAAC;IAED;;;;;;;OAOG;IACK,KAAK,CAAC,QAAQ,CACrB,eAAmD,EACnD,aAAiD,EACjD,UAAyB,EACzB,SAAiB;QAEjB,IAAI,aAA4B,CAAC;QACjC,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC/B,aAAa,GAAG,UAAU,CAAC;QAC5B,CAAC;aAAM,IAAI,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,oBAAoB,CAAC,EAAE,CAAC;YAChE,aAAa,GAAG,EAAE,CAAC;QACpB,CAAC;aAAM,CAAC;YACP,aAAa,GAAG,CAAC,EAAE,CAAC,CAAC;QACtB,CAAC;QAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/C,MAAM,YAAY,GAAG,eAAe,CAAC,kBAAkB,CACtD,aAAa,CAAC,CAAC,CAAC,EAChB,eAAe,CAAC,oBAAoB,EACpC,+BAA+B,CAAC,oBAAoB,CACpD,CAAC;YAEF,MAAM,gBAAgB,GAAG,eAAe,CAAC,gBAAgB,CAAC,UAAU,CACnE,eAAe,CAAC,cAAc,CAAC,YAAY,CAAC,CAC5C,CAAC;YACF,MAAM,cAAc,GAAG,aAAa,CAAC,gBAAgB,CAAC,UAAU,CAC/D,aAAa,CAAC,cAAc,CAAC,YAAY,CAAC,CAC1C,CAAC;YAEF,IAAI,OAAqC,CAAC;YAC1C,IAAI,OAAO,GAAG,IAAI,CAAC;YAEnB,OAAO,OAAO,EAAE,CAAC;gBAChB,IAAI,SAAS,GAAG,gBAAgB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;gBAClD,IAAI,OAAO,EAAE,CAAC;oBACb,SAAS,GAAG,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;gBAC3C,CAAC;gBACD,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,CAAC;gBACvC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC;gBAE3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,SAAS,EAAE,CAAC;oBACjD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC;oBAC3C,MAAM,KAAK,GAAG,aAAa,CAAC,gBAAgB,CAAC,KAAK,EAAE,CAAC;oBACrD,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;wBACzB,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;oBACnD,CAAC;oBACD,MAAM,KAAK,CAAC,MAAM,EAAE,CAAC;gBACtB,CAAC;gBAED,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;gBAChC,OAAO,GAAG,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC;YACrC,CAAC;QACF,CAAC;IACF,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,6BAA6B,CAAC,cAAsB;QACjE,MAAM,MAAM,GAAG,GAAG,cAAc,GAAG,CAAC;QACpC,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,eAAe,EAAE,CAAC;QAClE,MAAM,SAAS,GAAG,GAAG,CAAC;QACtB,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;YAC/B,IAAI,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC/B,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC;gBACjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,SAAS,EAAE,CAAC;oBAC1D,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC;oBACpD,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,CAAC;oBAC5C,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;wBACzB,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;oBACvB,CAAC;oBACD,MAAM,KAAK,CAAC,MAAM,EAAE,CAAC;gBACtB,CAAC;YACF,CAAC;QACF,CAAC;IACF,CAAC;IAED;;;;;;;;;OASG;IACK,mBAAmB,CAAC,SAA8B;QACzD,IAAI,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;YACzB,OAAO,KAAK,CAAC;QACd,CAAC;QACD,IAAI,YAAY,IAAI,SAAS,EAAE,CAAC;YAC/B,OAAO,SAAS,CAAC,eAAe,KAAK,eAAe,CAAC,EAAE;gBACtD,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;gBAC9D,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC;QAChE,CAAC;QACD,OAAO,CACN,SAAS,CAAC,UAAU,KAAK,kBAAkB,CAAC,EAAE;YAC9C,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC;YACzB,SAAS,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAC5B,CAAC;IACH,CAAC;IAED;;;;;;;;;OASG;IACK,sBAAsB,CAAC,SAA6B;QAC3D,IAAI,CAAC,CAAC,YAAY,IAAI,SAAS,CAAC,EAAE,CAAC;YAClC,IACC,SAAS,CAAC,UAAU,KAAK,kBAAkB,CAAC,EAAE;gBAC9C,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC;gBACzB,SAAS,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAC3B,CAAC;gBACF,OAAO,IAAI,CAAC;YACb,CAAC;YACD,OAAO,SAAS,CAAC;QAClB,CAAC;QACD,uEAAuE;QACvE,sEAAsE;QACtE,iEAAiE;QACjE,IAAI,SAAS,CAAC,eAAe,KAAK,eAAe,CAAC,EAAE,IAAI,IAAI,CAAC,mBAAmB,CAAC,SAAS,CAAC,EAAE,CAAC;YAC7F,OAAO,IAAI,CAAC;QACb,CAAC;QACD,uEAAuE;QACvE,uDAAuD;QACvD,MAAM,MAAM,GAAG,SAAS,CAAC,UAAU;aACjC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;aACxC,MAAM,CAAC,CAAC,CAAC,EAA2B,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;QACrD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC;QACb,CAAC;QACD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,OAAO,EAAE,GAAG,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;IAC7C,CAAC;IAED;;;;;;OAMG;IACK,eAAe,CAAC,SAA8B;QACrD,IAAI,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;YACzB,OAAO,KAAK,CAAC;QACd,CAAC;QACD,IAAI,YAAY,IAAI,SAAS,EAAE,CAAC;YAC/B,OAAO,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;QAChE,CAAC;QACD,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC;QACxC,IAAI,UAAU,KAAK,kBAAkB,CAAC,WAAW,EAAE,CAAC;YACnD,OAAO,IAAI,CAAC;QACb,CAAC;QACD,2FAA2F;QAC3F,4EAA4E;QAC5E,IACC,UAAU,KAAK,kBAAkB,CAAC,QAAQ;YAC1C,CAAC,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,CAAC,EAC5C,CAAC;YACF,OAAO,IAAI,CAAC;QACb,CAAC;QACD,OAAO,KAAK,CAAC;IACd,CAAC;IAED;;;;;;;OAOG;IACK,eAAe,CAAC,KAAY,EAAE,SAA6B;QAClE,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC;IACjD,CAAC;IAED;;;;;;OAMG;IACK,WAAW,CAAC,SAA6B;QAChD,IAAI,YAAY,IAAI,SAAS,EAAE,CAAC;YAC/B,MAAM,OAAO,GAAG,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;YACnE,OAAO,SAAS,CAAC,eAAe,KAAK,eAAe,CAAC,EAAE;gBACtD,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC;gBACvB,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC;QAC3B,CAAC;QACD,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,SAAS,CAAC;QAC3C,oEAAoE;QACpE,kEAAkE;QAClE,sEAAsE;QACtE,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC;QACrE,QAAQ,UAAU,EAAE,CAAC;YACpB,KAAK,kBAAkB,CAAC,MAAM;gBAC7B,OAAO,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;YAC5C,KAAK,kBAAkB,CAAC,SAAS;gBAChC,OAAO,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;YAC5C,KAAK,kBAAkB,CAAC,WAAW;gBAClC,OAAO,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;YAC3C,KAAK,kBAAkB,CAAC,QAAQ;gBAC/B,OAAO,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;YAC3C,KAAK,kBAAkB,CAAC,kBAAkB;gBACzC,OAAO,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;YAC5C,KAAK,kBAAkB,CAAC,eAAe;gBACtC,OAAO,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;YAC5C,KAAK,kBAAkB,CAAC,EAAE;gBACzB,OAAO,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;YAC5C,KAAK,kBAAkB,CAAC,QAAQ;gBAC/B,+EAA+E;gBAC/E,OAAO,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,gBAAgB,EAAE,KAAK,CAAC,CAAC;YACxD,KAAK,kBAAkB,CAAC,WAAW,CAAC;YACpC;gBACC,MAAM,IAAI,YAAY,CACrB,+BAA+B,CAAC,UAAU,EAC1C,+BAA+B,EAC/B,EAAE,UAAU,EAAE,CACd,CAAC;QACJ,CAAC;IACF,CAAC;IAED;;;;OAIG;IACK,cAAc,CAAC,YAAqB;QAC3C,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,IAAI,YAAY,IAAI,SAAS,EAAE,CAAC;IACtE,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport {\n\ttype DocumentSnapshot,\n\tFilter,\n\tFirestore,\n\ttype Query,\n\ttype Settings\n} from \"@google-cloud/firestore\";\nimport { ContextIdHelper, ContextIdStore, type IContextIds } from \"@twin.org/context\";\nimport {\n\tBaseError,\n\tComponentFactory,\n\tConverter,\n\tGeneralError,\n\tGuards,\n\tHealthStatus,\n\ttype IHealth,\n\tIs,\n\tObjectHelper\n} from \"@twin.org/core\";\nimport {\n\tComparisonOperator,\n\ttype EntityCondition,\n\tEntityConditions,\n\tEntitySchemaFactory,\n\tEntitySchemaHelper,\n\ttype IEntitySchema,\n\ttype IEntitySchemaProperty,\n\tLogicalOperator,\n\tSortDirection\n} from \"@twin.org/entity\";\nimport {\n\tEntityStorageHelper,\n\ttype IEntityStorageConnector,\n\ttype IEntityStorageMigrationConnector,\n\ttype IMigrationOptions\n} from \"@twin.org/entity-storage-models\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport type { JWTInput } from \"google-auth-library\";\nimport type { IFirestoreEntityStorageConnectorConfig } from \"./models/IFirestoreEntityStorageConnectorConfig.js\";\nimport type { IFirestoreEntityStorageConnectorConstructorOptions } from \"./models/IFirestoreEntityStorageConnectorConstructorOptions.js\";\n\n/**\n * Class for performing entity storage operations using Firestore.\n */\nexport class FirestoreEntityStorageConnector<\n\tT = unknown\n> implements IEntityStorageMigrationConnector<T> {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<FirestoreEntityStorageConnector>();\n\n\t/**\n\t * Limit the number of entities when finding.\n\t * @internal\n\t */\n\tprivate static readonly _DEFAULT_LIMIT: number = 40;\n\n\t/**\n\t * Separator used between context ID parts in Firestore collection names.\n\t * Must not be \"/\" which Firestore interprets as a path separator.\n\t * @internal\n\t */\n\tprivate static readonly _PARTITION_SEPARATOR: string = \":\";\n\n\t/**\n\t * The name for the schema.\n\t * @internal\n\t */\n\tprivate readonly _entitySchemaName: string;\n\n\t/**\n\t * The schema for the entity.\n\t * @internal\n\t */\n\tprivate readonly _entitySchema: IEntitySchema<T>;\n\n\t/**\n\t * The keys to use from the context ids to create partitions.\n\t * @internal\n\t */\n\tprivate readonly _partitionContextIds?: string[];\n\n\t/**\n\t * The primary key.\n\t * @internal\n\t */\n\tprivate readonly _primaryKey: IEntitySchemaProperty<T>;\n\n\t/**\n\t * The configuration for the connector.\n\t * @internal\n\t */\n\tprivate readonly _config: IFirestoreEntityStorageConnectorConfig;\n\n\t/**\n\t * The Firestore client.\n\t * @internal\n\t */\n\tprivate readonly _firestoreClient: Firestore;\n\n\t/**\n\t * Create a new instance of FirestoreEntityStorageConnector.\n\t * @param options The options for the connector.\n\t */\n\tconstructor(options: IFirestoreEntityStorageConnectorConstructorOptions) {\n\t\tGuards.object(FirestoreEntityStorageConnector.CLASS_NAME, nameof(options), options);\n\t\tGuards.stringValue(\n\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.entitySchema),\n\t\t\toptions.entitySchema\n\t\t);\n\t\tGuards.object<IFirestoreEntityStorageConnectorConfig>(\n\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config),\n\t\t\toptions.config\n\t\t);\n\t\tGuards.stringValue(\n\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config.projectId),\n\t\t\toptions.config.projectId\n\t\t);\n\t\tGuards.stringValue(\n\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config.collectionName),\n\t\t\toptions.config.collectionName\n\t\t);\n\n\t\tlet credentials: JWTInput | undefined;\n\t\tif (!Is.empty(options.config.credentials)) {\n\t\t\tGuards.stringBase64(\n\t\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\tnameof(options.config.credentials),\n\t\t\t\toptions.config.credentials\n\t\t\t);\n\t\t\tcredentials = ObjectHelper.fromBytes<JWTInput>(\n\t\t\t\tConverter.base64ToBytes(options.config.credentials)\n\t\t\t);\n\t\t}\n\n\t\tthis._config = options.config;\n\t\tthis._entitySchemaName = options.entitySchema;\n\t\tthis._entitySchema = EntitySchemaFactory.get(options.entitySchema);\n\t\tthis._partitionContextIds = options.partitionContextIds;\n\t\tthis._primaryKey = EntitySchemaHelper.getPrimaryKey<T>(this._entitySchema);\n\n\t\tconst firestoreOptions: Settings = {\n\t\t\tprojectId: this._config.projectId,\n\t\t\tdatabaseId: this._config.databaseId,\n\t\t\tcollectionName: this._config.collectionName,\n\t\t\tmaxIdleChannels: this._config.settings?.maxIdleChannels,\n\t\t\ttimeout: this._config.settings?.timeout,\n\t\t\tcredentials\n\t\t};\n\n\t\tif (Is.stringValue(this._config.endpoint)) {\n\t\t\tfirestoreOptions.host = this._config.endpoint;\n\t\t\tfirestoreOptions.ssl = false;\n\t\t}\n\n\t\tthis._firestoreClient = new Firestore(firestoreOptions);\n\t}\n\n\t/**\n\t * Returns the class name of the component.\n\t * @returns The class name of the component.\n\t */\n\tpublic className(): string {\n\t\treturn FirestoreEntityStorageConnector.CLASS_NAME;\n\t}\n\n\t/**\n\t * Returns the health status of the component.\n\t * @returns The health status of the component.\n\t */\n\tpublic async health(): Promise<IHealth[]> {\n\t\ttry {\n\t\t\tawait this._firestoreClient.listCollections();\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tsource: FirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\tstatus: HealthStatus.Ok,\n\t\t\t\t\tdescription: \"healthDescription\",\n\t\t\t\t\tdata: { projectId: this._config.projectId, collectionName: this._config.collectionName }\n\t\t\t\t}\n\t\t\t];\n\t\t} catch {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tsource: FirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\tstatus: HealthStatus.Error,\n\t\t\t\t\tdescription: \"healthDescription\",\n\t\t\t\t\tmessage: \"connectionFailed\",\n\t\t\t\t\tdata: { projectId: this._config.projectId, collectionName: this._config.collectionName }\n\t\t\t\t}\n\t\t\t];\n\t\t}\n\t}\n\n\t/**\n\t * Get the schema for the entities.\n\t * @returns The schema for the entities.\n\t */\n\tpublic getSchema(): IEntitySchema {\n\t\treturn this._entitySchema as IEntitySchema;\n\t}\n\n\t/**\n\t * Bootstrap the component by creating and initializing any resources it needs.\n\t * @param nodeLoggingComponentType The node logging component type.\n\t * @returns True if the bootstrapping process was successful.\n\t */\n\tpublic async bootstrap(nodeLoggingComponentType?: string): Promise<boolean> {\n\t\tconst nodeLogging = ComponentFactory.getIfExists<ILoggingComponent>(nodeLoggingComponentType);\n\n\t\ttry {\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: FirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"firestoreCreating\",\n\t\t\t\tdata: {\n\t\t\t\t\tprojectId: this._config.projectId,\n\t\t\t\t\tcollectionName: this._config.collectionName\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Firestore doesn't require explicit collection creation\n\t\t\t// Perform a small write operation to ensure connectivity\n\t\t\tconst testDoc = this._firestoreClient.collection(this._config.collectionName).doc(\"test\");\n\t\t\tawait testDoc.set({ test: true });\n\t\t\tawait testDoc.delete();\n\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: FirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"firestoreCreated\",\n\t\t\t\tdata: {\n\t\t\t\t\tprojectId: this._config.projectId,\n\t\t\t\t\tcollectionName: this._config.collectionName\n\t\t\t\t}\n\t\t\t});\n\n\t\t\treturn true;\n\t\t} catch (err) {\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"error\",\n\t\t\t\tsource: FirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"firestoreCreationFailed\",\n\t\t\t\terror: BaseError.fromError(err),\n\t\t\t\tdata: {\n\t\t\t\t\tprojectId: this._config.projectId,\n\t\t\t\t\tcollectionName: this._config.collectionName\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Get an entity.\n\t * @param id The id of the entity to get.\n\t * @param secondaryIndex The optional secondary index to use.\n\t * @param conditions The optional conditions to apply to the query.\n\t * @returns The object if it can be found or undefined.\n\t */\n\tpublic async get(\n\t\tid: string,\n\t\tsecondaryIndex?: keyof T,\n\t\tconditions?: { property: keyof T; value: unknown }[]\n\t): Promise<T | undefined> {\n\t\tGuards.stringValue(FirestoreEntityStorageConnector.CLASS_NAME, nameof(id), id);\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(\n\t\t\tcontextIds,\n\t\t\tthis._partitionContextIds,\n\t\t\tFirestoreEntityStorageConnector._PARTITION_SEPARATOR\n\t\t);\n\n\t\ttry {\n\t\t\tconst collection = this._firestoreClient.collection(this.collectionName(partitionKey));\n\n\t\t\tif (!Is.arrayValue(conditions)) {\n\t\t\t\tconst docRef = collection.doc(id);\n\t\t\t\tconst doc = await docRef.get();\n\n\t\t\t\tif (doc.exists) {\n\t\t\t\t\treturn EntityStorageHelper.unPrepareEntity<T>(doc.data() as T, []);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Use conditions to construct a query\n\t\t\tlet query: Query = collection;\n\n\t\t\tif (secondaryIndex) {\n\t\t\t\tquery = query.where(secondaryIndex as string, \"==\", id);\n\t\t\t} else {\n\t\t\t\t// If no secondaryIndex, include primary key in conditions\n\t\t\t\tquery = query.where(this._primaryKey.property as string, \"==\", id);\n\t\t\t}\n\n\t\t\tif (Is.arrayValue(conditions)) {\n\t\t\t\tfor (const condition of conditions) {\n\t\t\t\t\tquery = query.where(condition.property as string, \"==\", condition.value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst querySnapshot = await query.limit(1).get();\n\t\t\tif (!querySnapshot.empty) {\n\t\t\t\treturn EntityStorageHelper.unPrepareEntity<T>(querySnapshot.docs[0].data() as T, []);\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"getEntityFailed\",\n\t\t\t\t{ id },\n\t\t\t\terr\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Set an entity.\n\t * @param entity The entity to set.\n\t * @param conditions The optional conditions to apply to the update.\n\t * @returns Nothing.\n\t */\n\tpublic async set(entity: T, conditions?: { property: keyof T; value: unknown }[]): Promise<void> {\n\t\tGuards.object(FirestoreEntityStorageConnector.CLASS_NAME, nameof(entity), entity);\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(\n\t\t\tcontextIds,\n\t\t\tthis._partitionContextIds,\n\t\t\tFirestoreEntityStorageConnector._PARTITION_SEPARATOR\n\t\t);\n\n\t\tconst prepared = EntityStorageHelper.prepareEntity(entity, this._entitySchema, undefined, {\n\t\t\tnullBehavior: \"nullify\"\n\t\t});\n\n\t\ttry {\n\t\t\tconst id = prepared[this._primaryKey.property] as string;\n\n\t\t\tconst collection = this._firestoreClient.collection(this.collectionName(partitionKey));\n\n\t\t\tconst docRef = collection.doc(id);\n\n\t\t\tif (!Is.arrayValue(conditions)) {\n\t\t\t\tawait docRef.set(prepared);\n\t\t\t} else {\n\t\t\t\tawait this._firestoreClient.runTransaction(async transaction => {\n\t\t\t\t\tconst docSnapshot = await transaction.get(docRef);\n\n\t\t\t\t\tif (!docSnapshot.exists) {\n\t\t\t\t\t\ttransaction.set(docRef, prepared as object);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst data = docSnapshot.data() as T;\n\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tEntityConditions.check(data, {\n\t\t\t\t\t\t\t\tconditions: conditions.map(c => ({\n\t\t\t\t\t\t\t\t\tproperty: c.property as string,\n\t\t\t\t\t\t\t\t\tcomparison: ComparisonOperator.Equals,\n\t\t\t\t\t\t\t\t\tvalue: c.value\n\t\t\t\t\t\t\t\t}))\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\ttransaction.set(docRef, prepared as object);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"setEntityFailed\",\n\t\t\t\t{ id: entity.id },\n\t\t\t\terr\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Set multiple entities in a batch.\n\t * @param entities The entities to set.\n\t * @returns Nothing.\n\t */\n\tpublic async setBatch(entities: T[]): Promise<void> {\n\t\tGuards.arrayValue(FirestoreEntityStorageConnector.CLASS_NAME, nameof(entities), entities);\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(\n\t\t\tcontextIds,\n\t\t\tthis._partitionContextIds,\n\t\t\tFirestoreEntityStorageConnector._PARTITION_SEPARATOR\n\t\t);\n\n\t\tconst preparedEntities = entities.map(entity =>\n\t\t\tEntityStorageHelper.prepareEntity(entity, this._entitySchema, undefined, {\n\t\t\t\tnullBehavior: \"nullify\"\n\t\t\t})\n\t\t);\n\n\t\ttry {\n\t\t\tconst collection = this._firestoreClient.collection(this.collectionName(partitionKey));\n\t\t\tconst chunkSize = FirestoreEntityStorageConnector._DEFAULT_LIMIT;\n\t\t\tfor (let i = 0; i < preparedEntities.length; i += chunkSize) {\n\t\t\t\tconst chunk = preparedEntities.slice(i, i + chunkSize);\n\t\t\t\tconst batch = this._firestoreClient.batch();\n\t\t\t\tfor (const entity of chunk) {\n\t\t\t\t\tconst id = entity[this._primaryKey.property] as string;\n\t\t\t\t\tconst docRef = collection.doc(id);\n\t\t\t\t\tbatch.set(docRef, entity as { [key: string]: unknown });\n\t\t\t\t}\n\t\t\t\tawait batch.commit();\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"setBatchFailed\",\n\t\t\t\tundefined,\n\t\t\t\terr\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Empty the storage by deleting all entities in the collection.\n\t * @returns Nothing.\n\t */\n\tpublic async empty(): Promise<void> {\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(\n\t\t\tcontextIds,\n\t\t\tthis._partitionContextIds,\n\t\t\tFirestoreEntityStorageConnector._PARTITION_SEPARATOR\n\t\t);\n\n\t\ttry {\n\t\t\tconst collection = this._firestoreClient.collection(this.collectionName(partitionKey));\n\t\t\tconst snapshot = await collection.get();\n\t\t\tconst chunkSize = 500;\n\t\t\tfor (let i = 0; i < snapshot.docs.length; i += chunkSize) {\n\t\t\t\tconst chunk = snapshot.docs.slice(i, i + chunkSize);\n\t\t\t\tconst batch = this._firestoreClient.batch();\n\t\t\t\tfor (const doc of chunk) {\n\t\t\t\t\tbatch.delete(doc.ref);\n\t\t\t\t}\n\t\t\t\tawait batch.commit();\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"emptyFailed\",\n\t\t\t\tundefined,\n\t\t\t\terr\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Remove the entity.\n\t * @param id The id of the entity to remove.\n\t * @param conditions The optional conditions to apply to the delete.\n\t * @returns Nothing.\n\t */\n\tpublic async remove(\n\t\tid: string,\n\t\tconditions?: { property: keyof T; value: unknown }[]\n\t): Promise<void> {\n\t\tGuards.stringValue(FirestoreEntityStorageConnector.CLASS_NAME, nameof(id), id);\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(\n\t\t\tcontextIds,\n\t\t\tthis._partitionContextIds,\n\t\t\tFirestoreEntityStorageConnector._PARTITION_SEPARATOR\n\t\t);\n\n\t\ttry {\n\t\t\tconst collection = this._firestoreClient.collection(this.collectionName(partitionKey));\n\t\t\tconst docRef = collection.doc(id);\n\n\t\t\tif (!Is.arrayValue(conditions)) {\n\t\t\t\tawait docRef.delete();\n\t\t\t} else {\n\t\t\t\tawait this._firestoreClient.runTransaction(async transaction => {\n\t\t\t\t\tconst docSnapshot = await transaction.get(docRef);\n\n\t\t\t\t\tif (docSnapshot.exists) {\n\t\t\t\t\t\tconst data = docSnapshot.data() as T;\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tEntityConditions.check(data, {\n\t\t\t\t\t\t\t\tconditions: conditions.map(c => ({\n\t\t\t\t\t\t\t\t\tproperty: c.property as string,\n\t\t\t\t\t\t\t\t\tcomparison: ComparisonOperator.Equals,\n\t\t\t\t\t\t\t\t\tvalue: c.value\n\t\t\t\t\t\t\t\t}))\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\ttransaction.delete(docRef);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"removeEntityFailed\",\n\t\t\t\t{ id },\n\t\t\t\terr\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Remove multiple entities by their primary key IDs using a Firestore WriteBatch.\n\t * @param ids The ids of the entities to remove.\n\t * @returns Nothing.\n\t */\n\tpublic async removeBatch(ids: string[]): Promise<void> {\n\t\tGuards.arrayValue(FirestoreEntityStorageConnector.CLASS_NAME, nameof(ids), ids);\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(\n\t\t\tcontextIds,\n\t\t\tthis._partitionContextIds,\n\t\t\tFirestoreEntityStorageConnector._PARTITION_SEPARATOR\n\t\t);\n\n\t\ttry {\n\t\t\tconst collection = this._firestoreClient.collection(this.collectionName(partitionKey));\n\t\t\tconst chunkSize = 500;\n\t\t\tfor (let i = 0; i < ids.length; i += chunkSize) {\n\t\t\t\tconst chunk = ids.slice(i, i + chunkSize);\n\t\t\t\tconst batch = this._firestoreClient.batch();\n\t\t\t\tfor (const id of chunk) {\n\t\t\t\t\tconst docRef = collection.doc(id);\n\t\t\t\t\tbatch.delete(docRef);\n\t\t\t\t}\n\t\t\t\tawait batch.commit();\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"removeBatchFailed\",\n\t\t\t\tundefined,\n\t\t\t\terr\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Teardown the storage by deleting all documents across all partition collections.\n\t * @param nodeLoggingComponentType The node logging component type.\n\t * @returns True if the teardown process was successful.\n\t */\n\tpublic async teardown(nodeLoggingComponentType?: string): Promise<boolean> {\n\t\tconst nodeLogging = ComponentFactory.getIfExists<ILoggingComponent>(nodeLoggingComponentType);\n\n\t\tawait nodeLogging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: FirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: \"storeTearingDown\"\n\t\t});\n\n\t\ttry {\n\t\t\tawait this.deleteAllPartitionCollections(this._config.collectionName);\n\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: FirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"storeTornDown\"\n\t\t\t});\n\n\t\t\treturn true;\n\t\t} catch (err) {\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"error\",\n\t\t\t\tsource: FirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"teardownFailed\",\n\t\t\t\terror: BaseError.fromError(err)\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Get a unique list of all the context ids from the storage.\n\t * @returns The list of unique context ids.\n\t */\n\tpublic async getPartitionContextIds(): Promise<IContextIds[]> {\n\t\tconst partitionContextIds = this._partitionContextIds;\n\t\tif (!Is.arrayValue(partitionContextIds)) {\n\t\t\treturn [];\n\t\t}\n\t\ttry {\n\t\t\tconst prefix = `${this._config.collectionName}_`;\n\t\t\tconst collections = await this._firestoreClient.listCollections();\n\t\t\tconst result: IContextIds[] = [];\n\t\t\tfor (const col of collections) {\n\t\t\t\tif (col.id.startsWith(prefix)) {\n\t\t\t\t\tconst partitionKey = col.id.slice(prefix.length);\n\t\t\t\t\tif (Is.stringValue(partitionKey)) {\n\t\t\t\t\t\tresult.push(\n\t\t\t\t\t\t\tContextIdHelper.shortSplit(\n\t\t\t\t\t\t\t\tpartitionContextIds,\n\t\t\t\t\t\t\t\tpartitionKey,\n\t\t\t\t\t\t\t\tFirestoreEntityStorageConnector._PARTITION_SEPARATOR\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn result;\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"getPartitionContextIdsFailed\",\n\t\t\t\tundefined,\n\t\t\t\terr\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Create the target connector for performing the migration using a temporary collection name.\n\t * @param newEntitySchema The name of the new entity schema to create the connector for.\n\t * @returns Connector for performing the migration.\n\t */\n\tpublic async createTargetConnector<U>(\n\t\tnewEntitySchema: string\n\t): Promise<IEntityStorageConnector<U>> {\n\t\tconst migrationCollectionName = `${this._config.collectionName}Migration${Date.now()}`;\n\t\treturn new FirestoreEntityStorageConnector<U>({\n\t\t\tentitySchema: newEntitySchema,\n\t\t\tconfig: { ...this._config, collectionName: migrationCollectionName },\n\t\t\tpartitionContextIds: this._partitionContextIds\n\t\t});\n\t}\n\n\t/**\n\t * Finalize the migration by tearing down the old collections and replacing them with the target collections.\n\t * @param targetConnector The target connector to finalize the migration with.\n\t * @param options The options to control how the migration is finalized.\n\t * @param loggingComponentType The optional component type to use for logging.\n\t * @returns The final connector pointing at the original collection name.\n\t */\n\tpublic async finalizeMigration<U>(\n\t\ttargetConnector: FirestoreEntityStorageConnector<U>,\n\t\toptions?: IMigrationOptions<T, U>,\n\t\tloggingComponentType?: string\n\t): Promise<FirestoreEntityStorageConnector<U>> {\n\t\t// Firestore has no collection-rename operation, so we create fresh collections under\n\t\t// the original name, copy all documents from the migration collections, then delete the\n\t\t// migration collections.\n\n\t\t// Teardown all existing source collections to free up the original collection name prefix.\n\t\tawait this.teardown(loggingComponentType);\n\n\t\t// Create a new connector at the original collection name but with the new schema.\n\t\tconst originalCollectionName = this._config.collectionName;\n\t\tconst finalConnector = new FirestoreEntityStorageConnector<U>({\n\t\t\tentitySchema: targetConnector._entitySchemaName,\n\t\t\tconfig: { ...targetConnector._config, collectionName: originalCollectionName },\n\t\t\tpartitionContextIds: this._partitionContextIds\n\t\t});\n\n\t\tif (await finalConnector.bootstrap(loggingComponentType)) {\n\t\t\t// Since there is no rename, we need to copy the data from the migration table to the new table\n\t\t\tconst partitions = await targetConnector.getPartitionContextIds();\n\t\t\tconst batchSize = options?.batchSize ?? FirestoreEntityStorageConnector._DEFAULT_LIMIT;\n\t\t\tawait this.bulkCopy(targetConnector, finalConnector, partitions, batchSize);\n\n\t\t\tawait targetConnector.teardown(loggingComponentType);\n\n\t\t\treturn finalConnector;\n\t\t}\n\t\tthrow new GeneralError(\n\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\"finalizeMigrationFailedBootstrap\",\n\t\t\tundefined\n\t\t);\n\t}\n\n\t/**\n\t * Cleanup the migration if a migration fails or needs to be aborted.\n\t * @param targetConnector The target connector to cleanup.\n\t * @param options The options to control how the migration is cleaned up.\n\t * @param loggingComponentType The optional component type to use for logging.\n\t */\n\tpublic async cleanupMigration<U>(\n\t\ttargetConnector: IEntityStorageConnector<U> | undefined,\n\t\toptions?: IMigrationOptions<T, U>,\n\t\tloggingComponentType?: string\n\t): Promise<void> {\n\t\t// If something failed the only thing to cleanup is the migration table\n\t\tawait targetConnector?.teardown?.(loggingComponentType);\n\t}\n\n\t/**\n\t * Find all the entities which match the conditions.\n\t * @param conditions The conditions to match for the entities.\n\t * @param sortProperties The optional sort order.\n\t * @param properties The optional properties to return, defaults to all.\n\t * @param cursor The cursor to request the next chunk of entities.\n\t * @param limit The suggested number of entities to return in each chunk.\n\t * @returns The matching entities and a cursor for the next page.\n\t */\n\tpublic async query(\n\t\tconditions?: EntityCondition<T>,\n\t\tsortProperties?: { property: keyof T; sortDirection: SortDirection }[],\n\t\tproperties?: (keyof T)[],\n\t\tcursor?: string,\n\t\tlimit?: number\n\t): Promise<{\n\t\t/**\n\t\t * The entities, which can be partial if a limited keys list was provided.\n\t\t */\n\t\tentities: Partial<T>[];\n\t\t/**\n\t\t * An optional cursor, when defined can be used to call find to get more entities.\n\t\t */\n\t\tcursor?: string;\n\t}> {\n\t\tconst queryDescription: string[] = [];\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(\n\t\t\tcontextIds,\n\t\t\tthis._partitionContextIds,\n\t\t\tFirestoreEntityStorageConnector._PARTITION_SEPARATOR\n\t\t);\n\n\t\tconst finalLimit = limit ?? FirestoreEntityStorageConnector._DEFAULT_LIMIT;\n\n\t\ttry {\n\t\t\tconst collection = this._firestoreClient.collection(this.collectionName(partitionKey));\n\n\t\t\t// Firestore has no native substring search. When any condition needs in-memory\n\t\t\t// filtering (string Includes / NotIncludes), fetch all matching docs and filter\n\t\t\t// client-side, using an index-based cursor for pagination.\n\t\t\tif (!Is.empty(conditions) && this.needsPostFilter(conditions)) {\n\t\t\t\tqueryDescription.push(\"InMemoryFilter\");\n\n\t\t\t\tlet baseQuery = collection as Query;\n\n\t\t\t\tif (Is.arrayValue(sortProperties)) {\n\t\t\t\t\tfor (const { property, sortDirection } of sortProperties) {\n\t\t\t\t\t\tbaseQuery = baseQuery.orderBy(\n\t\t\t\t\t\t\tproperty as string,\n\t\t\t\t\t\t\tsortDirection === SortDirection.Ascending ? \"asc\" : \"desc\"\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst allSnapshot = await baseQuery.get();\n\t\t\t\tlet allEntities = allSnapshot.docs.map((doc: DocumentSnapshot) =>\n\t\t\t\t\tEntityStorageHelper.unPrepareEntity<T>(doc.data() as T, [])\n\t\t\t\t);\n\n\t\t\t\tallEntities = allEntities.filter(e => EntityConditions.check(e as Partial<T>, conditions));\n\n\t\t\t\tlet projected: Partial<T>[];\n\t\t\t\tif (Is.arrayValue(properties)) {\n\t\t\t\t\tprojected = allEntities.map(e => {\n\t\t\t\t\t\tconst out: Partial<T> = {};\n\t\t\t\t\t\tfor (const prop of properties) {\n\t\t\t\t\t\t\tif (prop in (e as object)) {\n\t\t\t\t\t\t\t\tout[prop] = e[prop];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn out;\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tprojected = allEntities;\n\t\t\t\t}\n\n\t\t\t\tconst start = Is.stringValue(cursor) ? Number.parseInt(cursor, 10) : 0;\n\t\t\t\tconst page = projected.slice(start, start + finalLimit);\n\t\t\t\tconst nextCursor =\n\t\t\t\t\tstart + finalLimit < projected.length ? String(start + finalLimit) : undefined;\n\n\t\t\t\treturn { entities: page, cursor: nextCursor };\n\t\t\t}\n\n\t\t\tif (this.hasEmptyInCondition(conditions)) {\n\t\t\t\treturn { entities: [], cursor: undefined };\n\t\t\t}\n\n\t\t\t// Prune empty-In leaves from OR branches: the Firestore SDK throws on\n\t\t\t// Filter.where(prop, \"in\", []) even inside an OR where other branches still match.\n\t\t\t// hasEmptyInCondition above already handles the all-false case, so pruning here\n\t\t\t// is safe — any removed leaf was a no-op branch.\n\t\t\tconst effectiveConditions = !Is.empty(conditions)\n\t\t\t\t? (this.pruneEmptyInConditions(conditions) ?? undefined)\n\t\t\t\t: conditions;\n\n\t\t\tlet query = collection as Query;\n\n\t\t\tif (!Is.empty(effectiveConditions)) {\n\t\t\t\tquery = this.applyConditions(query, effectiveConditions);\n\t\t\t\tqueryDescription.push(`Conditions: ${JSON.stringify(conditions)}`);\n\t\t\t}\n\n\t\t\tif (Is.arrayValue(sortProperties)) {\n\t\t\t\tfor (const { property, sortDirection } of sortProperties) {\n\t\t\t\t\tquery = query.orderBy(\n\t\t\t\t\t\tproperty as string,\n\t\t\t\t\t\tsortDirection === SortDirection.Ascending ? \"asc\" : \"desc\"\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tqueryDescription.push(`Sort: ${JSON.stringify(sortProperties)}`);\n\t\t\t}\n\n\t\t\tif (Is.stringValue(cursor)) {\n\t\t\t\tconst cursorDoc = await this._firestoreClient.doc(cursor).get();\n\t\t\t\tif (cursorDoc?.exists) {\n\t\t\t\t\tquery = query.startAfter(cursorDoc);\n\t\t\t\t}\n\t\t\t\tqueryDescription.push(`Cursor: ${cursor}`);\n\t\t\t}\n\n\t\t\tquery = query.limit(finalLimit + 1);\n\t\t\tqueryDescription.push(`Limit: ${finalLimit}`);\n\n\t\t\tif (Is.arrayValue(properties)) {\n\t\t\t\tquery = query.select(...(properties as string[]));\n\t\t\t\tqueryDescription.push(`Properties: ${properties.join(\", \")}`);\n\t\t\t}\n\n\t\t\tconst querySnapshot = await query.get();\n\t\t\tconst hasMore = querySnapshot.docs.length > finalLimit;\n\t\t\tconst resultDocs = hasMore ? querySnapshot.docs.slice(0, finalLimit) : querySnapshot.docs;\n\t\t\tconst entities = resultDocs.map((doc: DocumentSnapshot) =>\n\t\t\t\tEntityStorageHelper.unPrepareEntity<T>(doc.data() as T, [])\n\t\t\t);\n\n\t\t\tlet nextCursor: string | undefined;\n\t\t\tif (hasMore) {\n\t\t\t\tnextCursor = resultDocs[resultDocs.length - 1].ref.path;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tentities,\n\t\t\t\tcursor: nextCursor\n\t\t\t};\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"queryFailed\",\n\t\t\t\t{ queryDescription: queryDescription.join(\"; \") },\n\t\t\t\terr\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Count all the entities which match the conditions.\n\t * @param conditions The optional conditions to match for the entities.\n\t * @returns The total count of entities in the storage.\n\t */\n\tpublic async count(conditions?: EntityCondition<T>): Promise<number> {\n\t\ttry {\n\t\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\t\tconst partitionKey = ContextIdHelper.combinedContextKey(\n\t\t\t\tcontextIds,\n\t\t\t\tthis._partitionContextIds,\n\t\t\t\tFirestoreEntityStorageConnector._PARTITION_SEPARATOR\n\t\t\t);\n\n\t\t\tconst collection = this._firestoreClient.collection(this.collectionName(partitionKey));\n\n\t\t\tif (this.hasEmptyInCondition(conditions)) {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tif (!Is.empty(conditions) && this.needsPostFilter(conditions)) {\n\t\t\t\tconst allSnapshot = await collection.get();\n\t\t\t\tconst allEntities = allSnapshot.docs.map((doc: DocumentSnapshot) =>\n\t\t\t\t\tEntityStorageHelper.unPrepareEntity<T>(doc.data() as T, [])\n\t\t\t\t);\n\t\t\t\treturn allEntities.filter(e => EntityConditions.check(e as Partial<T>, conditions)).length;\n\t\t\t}\n\n\t\t\tconst effectiveConditions = !Is.empty(conditions)\n\t\t\t\t? (this.pruneEmptyInConditions(conditions) ?? undefined)\n\t\t\t\t: conditions;\n\n\t\t\tlet query = collection as Query;\n\t\t\tif (!Is.empty(effectiveConditions)) {\n\t\t\t\tquery = this.applyConditions(query, effectiveConditions);\n\t\t\t}\n\n\t\t\tconst snapshot = await query.count().get();\n\t\t\treturn snapshot.data().count;\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"countFailed\",\n\t\t\t\tundefined,\n\t\t\t\terr\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Copy all entities from sourceConnector to destConnector, paging through each partition.\n\t * @param sourceConnector The connector to read entities from.\n\t * @param destConnector The connector to write entities to.\n\t * @param partitions The partition list returned by getPartitionContextIds.\n\t * @param batchSize The number of entities to read per page.\n\t * @internal\n\t */\n\tprivate async bulkCopy<U>(\n\t\tsourceConnector: FirestoreEntityStorageConnector<U>,\n\t\tdestConnector: FirestoreEntityStorageConnector<U>,\n\t\tpartitions: IContextIds[],\n\t\tbatchSize: number\n\t): Promise<void> {\n\t\tlet partitionList: IContextIds[];\n\t\tif (Is.arrayValue(partitions)) {\n\t\t\tpartitionList = partitions;\n\t\t} else if (Is.arrayValue(sourceConnector._partitionContextIds)) {\n\t\t\tpartitionList = [];\n\t\t} else {\n\t\t\tpartitionList = [{}];\n\t\t}\n\n\t\tfor (let i = 0; i < partitionList.length; i++) {\n\t\t\tconst partitionKey = ContextIdHelper.combinedContextKey(\n\t\t\t\tpartitionList[i],\n\t\t\t\tsourceConnector._partitionContextIds,\n\t\t\t\tFirestoreEntityStorageConnector._PARTITION_SEPARATOR\n\t\t\t);\n\n\t\t\tconst sourceCollection = sourceConnector._firestoreClient.collection(\n\t\t\t\tsourceConnector.collectionName(partitionKey)\n\t\t\t);\n\t\t\tconst destCollection = destConnector._firestoreClient.collection(\n\t\t\t\tdestConnector.collectionName(partitionKey)\n\t\t\t);\n\n\t\t\tlet lastDoc: DocumentSnapshot | undefined;\n\t\t\tlet hasMore = true;\n\n\t\t\twhile (hasMore) {\n\t\t\t\tlet pageQuery = sourceCollection.limit(batchSize);\n\t\t\t\tif (lastDoc) {\n\t\t\t\t\tpageQuery = pageQuery.startAfter(lastDoc);\n\t\t\t\t}\n\t\t\t\tconst snapshot = await pageQuery.get();\n\t\t\t\tconst docs = snapshot.docs;\n\n\t\t\t\tfor (let j = 0; j < docs.length; j += batchSize) {\n\t\t\t\t\tconst chunk = docs.slice(j, j + batchSize);\n\t\t\t\t\tconst batch = destConnector._firestoreClient.batch();\n\t\t\t\t\tfor (const doc of chunk) {\n\t\t\t\t\t\tbatch.set(destCollection.doc(doc.id), doc.data());\n\t\t\t\t\t}\n\t\t\t\t\tawait batch.commit();\n\t\t\t\t}\n\n\t\t\t\tlastDoc = docs[docs.length - 1];\n\t\t\t\thasMore = docs.length === batchSize;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Delete all documents in every collection whose name starts with collectionName_.\n\t * @param collectionName The base collection name prefix.\n\t * @internal\n\t */\n\tprivate async deleteAllPartitionCollections(collectionName: string): Promise<void> {\n\t\tconst prefix = `${collectionName}_`;\n\t\tconst collections = await this._firestoreClient.listCollections();\n\t\tconst chunkSize = 500;\n\t\tfor (const col of collections) {\n\t\t\tif (col.id.startsWith(prefix)) {\n\t\t\t\tconst snapshot = await col.get();\n\t\t\t\tfor (let i = 0; i < snapshot.docs.length; i += chunkSize) {\n\t\t\t\t\tconst chunk = snapshot.docs.slice(i, i + chunkSize);\n\t\t\t\t\tconst batch = this._firestoreClient.batch();\n\t\t\t\t\tfor (const doc of chunk) {\n\t\t\t\t\t\tbatch.delete(doc.ref);\n\t\t\t\t\t}\n\t\t\t\t\tawait batch.commit();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns true when the condition tree is guaranteed to match nothing due to empty\n\t * In lists, respecting AND/OR boolean semantics (#141):\n\t * - AND group: true if ANY child is always-false (false AND x = false)\n\t * - OR group: true if ALL children are always-false (false OR false = false)\n\t * - Leaf: true only for `In []`\n\t * @param condition The condition tree to inspect.\n\t * @returns True if a short-circuit to empty results is required.\n\t * @internal\n\t */\n\tprivate hasEmptyInCondition(condition?: EntityCondition<T>): boolean {\n\t\tif (Is.empty(condition)) {\n\t\t\treturn false;\n\t\t}\n\t\tif (\"conditions\" in condition) {\n\t\t\treturn condition.logicalOperator === LogicalOperator.Or\n\t\t\t\t? condition.conditions.every(c => this.hasEmptyInCondition(c))\n\t\t\t\t: condition.conditions.some(c => this.hasEmptyInCondition(c));\n\t\t}\n\t\treturn (\n\t\t\tcondition.comparison === ComparisonOperator.In &&\n\t\t\tIs.array(condition.value) &&\n\t\t\tcondition.value.length === 0\n\t\t);\n\t}\n\n\t/**\n\t * Returns a copy of the condition tree with all empty-In leaves removed.\n\t * Used to keep `In []` out of native Firestore Filter calls (the SDK throws on\n\t * `Filter.where(prop, \"in\", [])`) while preserving correct OR semantics (#141).\n\t * Returns null when the entire subtree reduces to nothing (caller should treat\n\t * as no conditions).\n\t * @param condition The condition to prune.\n\t * @returns The pruned condition, or null if the subtree was fully removed.\n\t * @internal\n\t */\n\tprivate pruneEmptyInConditions(condition: EntityCondition<T>): EntityCondition<T> | null {\n\t\tif (!(\"conditions\" in condition)) {\n\t\t\tif (\n\t\t\t\tcondition.comparison === ComparisonOperator.In &&\n\t\t\t\tIs.array(condition.value) &&\n\t\t\t\tcondition.value.length === 0\n\t\t\t) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn condition;\n\t\t}\n\t\t// For AND groups: if any child has an empty In, the whole AND is dead.\n\t\t// Do not recurse — promoting the surviving siblings would turn a dead\n\t\t// branch into a live one when this AND sits inside an OR (#141).\n\t\tif (condition.logicalOperator !== LogicalOperator.Or && this.hasEmptyInCondition(condition)) {\n\t\t\treturn null;\n\t\t}\n\t\t// For OR groups: prune dead branches individually so the Firestore SDK\n\t\t// never receives `In []`, while keeping live siblings.\n\t\tconst pruned = condition.conditions\n\t\t\t.map(c => this.pruneEmptyInConditions(c))\n\t\t\t.filter((c): c is EntityCondition<T> => c !== null);\n\t\tif (pruned.length === 0) {\n\t\t\treturn null;\n\t\t}\n\t\tif (pruned.length === 1) {\n\t\t\treturn pruned[0];\n\t\t}\n\t\treturn { ...condition, conditions: pruned };\n\t}\n\n\t/**\n\t * Returns true when any leaf condition requires client-side filtering\n\t * (Firestore has no native string-contains / not-contains operator).\n\t * @param condition The condition tree to inspect.\n\t * @returns True if post-filtering is required.\n\t * @internal\n\t */\n\tprivate needsPostFilter(condition?: EntityCondition<T>): boolean {\n\t\tif (Is.empty(condition)) {\n\t\t\treturn false;\n\t\t}\n\t\tif (\"conditions\" in condition) {\n\t\t\treturn condition.conditions.some(c => this.needsPostFilter(c));\n\t\t}\n\t\tconst { comparison, value } = condition;\n\t\tif (comparison === ComparisonOperator.NotIncludes) {\n\t\t\treturn true;\n\t\t}\n\t\t// Includes on a primitive (string/number) means substring search — not natively supported.\n\t\t// Includes on an object means array-contains, which Firestore does support.\n\t\tif (\n\t\t\tcomparison === ComparisonOperator.Includes &&\n\t\t\t(value === null || typeof value !== \"object\")\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Apply conditions to a Firestore query using composite Filter objects so that\n\t * OR groups are handled correctly.\n\t * @param query The initial query.\n\t * @param condition The condition to apply.\n\t * @returns The updated query.\n\t * @internal\n\t */\n\tprivate applyConditions(query: Query, condition: EntityCondition<T>): Query {\n\t\treturn query.where(this.buildFilter(condition));\n\t}\n\n\t/**\n\t * Recursively convert an EntityCondition tree into a Firestore Filter.\n\t * Only called for native conditions (needsPostFilter must be false).\n\t * @param condition The condition to convert.\n\t * @returns A Firestore Filter.\n\t * @internal\n\t */\n\tprivate buildFilter(condition: EntityCondition<T>): Filter {\n\t\tif (\"conditions\" in condition) {\n\t\t\tconst filters = condition.conditions.map(c => this.buildFilter(c));\n\t\t\treturn condition.logicalOperator === LogicalOperator.Or\n\t\t\t\t? Filter.or(...filters)\n\t\t\t\t: Filter.and(...filters);\n\t\t}\n\t\tconst { property, comparison } = condition;\n\t\t// Firestore has no undefined type — null has the correct semantics:\n\t\t// == null matches documents where the field is null OR missing\n\t\t// != null matches documents where the field exists and is not null\n\t\tconst value = condition.value === undefined ? null : condition.value;\n\t\tswitch (comparison) {\n\t\t\tcase ComparisonOperator.Equals:\n\t\t\t\treturn Filter.where(property, \"==\", value);\n\t\t\tcase ComparisonOperator.NotEquals:\n\t\t\t\treturn Filter.where(property, \"!=\", value);\n\t\t\tcase ComparisonOperator.GreaterThan:\n\t\t\t\treturn Filter.where(property, \">\", value);\n\t\t\tcase ComparisonOperator.LessThan:\n\t\t\t\treturn Filter.where(property, \"<\", value);\n\t\t\tcase ComparisonOperator.GreaterThanOrEqual:\n\t\t\t\treturn Filter.where(property, \">=\", value);\n\t\t\tcase ComparisonOperator.LessThanOrEqual:\n\t\t\t\treturn Filter.where(property, \"<=\", value);\n\t\t\tcase ComparisonOperator.In:\n\t\t\t\treturn Filter.where(property, \"in\", value);\n\t\t\tcase ComparisonOperator.Includes:\n\t\t\t\t// Object value → array-contains (caller ensured needsPostFilter is false here)\n\t\t\t\treturn Filter.where(property, \"array-contains\", value);\n\t\t\tcase ComparisonOperator.NotIncludes:\n\t\t\tdefault:\n\t\t\t\tthrow new GeneralError(\n\t\t\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\t\"unsupportedComparisonOperator\",\n\t\t\t\t\t{ comparison }\n\t\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Get the collection name based on partition key.\n\t * @returns The collection name.\n\t * @internal\n\t */\n\tprivate collectionName(partitionKey?: string): string {\n\t\treturn `${this._config.collectionName}_${partitionKey ?? \"default\"}`;\n\t}\n}\n"]}
1
+ {"version":3,"file":"firestoreEntityStorageConnector.js","sourceRoot":"","sources":["../../src/firestoreEntityStorageConnector.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport {\n\ttype DocumentSnapshot,\n\tFilter,\n\tFirestore,\n\ttype Query,\n\ttype Settings\n} from \"@google-cloud/firestore\";\nimport { ContextIdHelper, ContextIdStore, type IContextIds } from \"@twin.org/context\";\nimport {\n\tBaseError,\n\tComponentFactory,\n\tConverter,\n\tGeneralError,\n\tGuards,\n\tHealthStatus,\n\ttype IHealth,\n\tIs,\n\tObjectHelper\n} from \"@twin.org/core\";\nimport {\n\tComparisonOperator,\n\ttype EntityCondition,\n\tEntityConditions,\n\tEntitySchemaFactory,\n\tEntitySchemaHelper,\n\ttype IEntitySchema,\n\ttype IEntitySchemaProperty,\n\tLogicalOperator,\n\tSortDirection\n} from \"@twin.org/entity\";\nimport {\n\tEntityStorageHelper,\n\ttype IEntityStorageConnector,\n\ttype IEntityStorageMigrationConnector,\n\ttype IMigrationOptions\n} from \"@twin.org/entity-storage-models\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport type { JWTInput } from \"google-auth-library\";\nimport type { IFirestoreEntityStorageConnectorConfig } from \"./models/IFirestoreEntityStorageConnectorConfig.js\";\nimport type { IFirestoreEntityStorageConnectorConstructorOptions } from \"./models/IFirestoreEntityStorageConnectorConstructorOptions.js\";\n\n/**\n * Class for performing entity storage operations using Firestore.\n */\nexport class FirestoreEntityStorageConnector<\n\tT = unknown\n> implements IEntityStorageMigrationConnector<T> {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<FirestoreEntityStorageConnector>();\n\n\t/**\n\t * Limit the number of entities when finding.\n\t * @internal\n\t */\n\tprivate static readonly _DEFAULT_LIMIT: number = 40;\n\n\t/**\n\t * Separator used between context ID parts in Firestore collection names.\n\t * Must not be \"/\" which Firestore interprets as a path separator.\n\t * @internal\n\t */\n\tprivate static readonly _PARTITION_SEPARATOR: string = \":\";\n\n\t/**\n\t * The name for the schema.\n\t * @internal\n\t */\n\tprivate readonly _entitySchemaName: string;\n\n\t/**\n\t * The schema for the entity.\n\t * @internal\n\t */\n\tprivate readonly _entitySchema: IEntitySchema<T>;\n\n\t/**\n\t * The keys to use from the context ids to create partitions.\n\t * @internal\n\t */\n\tprivate readonly _partitionContextIds?: string[];\n\n\t/**\n\t * The primary key.\n\t * @internal\n\t */\n\tprivate readonly _primaryKey: IEntitySchemaProperty<T>;\n\n\t/**\n\t * The configuration for the connector.\n\t * @internal\n\t */\n\tprivate readonly _config: IFirestoreEntityStorageConnectorConfig;\n\n\t/**\n\t * The Firestore client.\n\t * @internal\n\t */\n\tprivate readonly _firestoreClient: Firestore;\n\n\t/**\n\t * Create a new instance of FirestoreEntityStorageConnector.\n\t * @param options The options for the connector.\n\t */\n\tconstructor(options: IFirestoreEntityStorageConnectorConstructorOptions) {\n\t\tGuards.object(FirestoreEntityStorageConnector.CLASS_NAME, nameof(options), options);\n\t\tGuards.stringValue(\n\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.entitySchema),\n\t\t\toptions.entitySchema\n\t\t);\n\t\tGuards.object<IFirestoreEntityStorageConnectorConfig>(\n\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config),\n\t\t\toptions.config\n\t\t);\n\t\tGuards.stringValue(\n\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config.projectId),\n\t\t\toptions.config.projectId\n\t\t);\n\t\tGuards.stringValue(\n\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config.collectionName),\n\t\t\toptions.config.collectionName\n\t\t);\n\n\t\tlet credentials: JWTInput | undefined;\n\t\tif (!Is.empty(options.config.credentials)) {\n\t\t\tGuards.stringBase64(\n\t\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\tnameof(options.config.credentials),\n\t\t\t\toptions.config.credentials\n\t\t\t);\n\t\t\tcredentials = ObjectHelper.fromBytes<JWTInput>(\n\t\t\t\tConverter.base64ToBytes(options.config.credentials)\n\t\t\t);\n\t\t}\n\n\t\tthis._config = options.config;\n\t\tthis._entitySchemaName = options.entitySchema;\n\t\tthis._entitySchema = EntitySchemaFactory.get(options.entitySchema);\n\t\tthis._partitionContextIds = options.partitionContextIds;\n\t\tthis._primaryKey = EntitySchemaHelper.getPrimaryKey<T>(this._entitySchema);\n\n\t\tconst firestoreOptions: Settings = {\n\t\t\tprojectId: this._config.projectId,\n\t\t\tdatabaseId: this._config.databaseId,\n\t\t\tcollectionName: this._config.collectionName,\n\t\t\tmaxIdleChannels: this._config.settings?.maxIdleChannels,\n\t\t\ttimeout: this._config.settings?.timeout,\n\t\t\tcredentials\n\t\t};\n\n\t\tif (Is.stringValue(this._config.endpoint)) {\n\t\t\tfirestoreOptions.host = this._config.endpoint;\n\t\t\tfirestoreOptions.ssl = false;\n\t\t}\n\n\t\tthis._firestoreClient = new Firestore(firestoreOptions);\n\t}\n\n\t/**\n\t * Returns the class name of the component.\n\t * @returns The class name of the component.\n\t */\n\tpublic className(): string {\n\t\treturn FirestoreEntityStorageConnector.CLASS_NAME;\n\t}\n\n\t/**\n\t * Returns the health status of the component.\n\t * @returns The health status of the component.\n\t */\n\tpublic async health(): Promise<IHealth[]> {\n\t\ttry {\n\t\t\tawait this._firestoreClient.listCollections();\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tsource: FirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\tstatus: HealthStatus.Ok,\n\t\t\t\t\tdescription: \"healthDescription\",\n\t\t\t\t\tdata: { projectId: this._config.projectId, collectionName: this._config.collectionName }\n\t\t\t\t}\n\t\t\t];\n\t\t} catch {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tsource: FirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\tstatus: HealthStatus.Error,\n\t\t\t\t\tdescription: \"healthDescription\",\n\t\t\t\t\tmessage: \"connectionFailed\",\n\t\t\t\t\tdata: { projectId: this._config.projectId, collectionName: this._config.collectionName }\n\t\t\t\t}\n\t\t\t];\n\t\t}\n\t}\n\n\t/**\n\t * Get the schema for the entities.\n\t * @returns The schema for the entities.\n\t */\n\tpublic getSchema(): IEntitySchema {\n\t\treturn this._entitySchema as IEntitySchema;\n\t}\n\n\t/**\n\t * Bootstrap the component by creating and initializing any resources it needs.\n\t * @param nodeLoggingComponentType The node logging component type.\n\t * @returns True if the bootstrapping process was successful.\n\t */\n\tpublic async bootstrap(nodeLoggingComponentType?: string): Promise<boolean> {\n\t\tconst nodeLogging = ComponentFactory.getIfExists<ILoggingComponent>(nodeLoggingComponentType);\n\n\t\ttry {\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: FirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"firestoreCreating\",\n\t\t\t\tdata: {\n\t\t\t\t\tprojectId: this._config.projectId,\n\t\t\t\t\tcollectionName: this._config.collectionName\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Firestore doesn't require explicit collection creation\n\t\t\t// Perform a small write operation to ensure connectivity\n\t\t\tconst testDoc = this._firestoreClient.collection(this._config.collectionName).doc(\"test\");\n\t\t\tawait testDoc.set({ test: true });\n\t\t\tawait testDoc.delete();\n\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: FirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"firestoreCreated\",\n\t\t\t\tdata: {\n\t\t\t\t\tprojectId: this._config.projectId,\n\t\t\t\t\tcollectionName: this._config.collectionName\n\t\t\t\t}\n\t\t\t});\n\n\t\t\treturn true;\n\t\t} catch (err) {\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"error\",\n\t\t\t\tsource: FirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"firestoreCreationFailed\",\n\t\t\t\terror: BaseError.fromError(err),\n\t\t\t\tdata: {\n\t\t\t\t\tprojectId: this._config.projectId,\n\t\t\t\t\tcollectionName: this._config.collectionName\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Get an entity.\n\t * @param id The id of the entity to get.\n\t * @param secondaryIndex The optional secondary index to use.\n\t * @param conditions The optional conditions to apply to the query.\n\t * @returns The object if it can be found or undefined.\n\t */\n\tpublic async get(\n\t\tid: string,\n\t\tsecondaryIndex?: keyof T,\n\t\tconditions?: { property: keyof T; value: unknown }[]\n\t): Promise<T | undefined> {\n\t\tGuards.stringValue(FirestoreEntityStorageConnector.CLASS_NAME, nameof(id), id);\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(\n\t\t\tcontextIds,\n\t\t\tthis._partitionContextIds,\n\t\t\tFirestoreEntityStorageConnector._PARTITION_SEPARATOR\n\t\t);\n\n\t\ttry {\n\t\t\tconst collection = this._firestoreClient.collection(this.collectionName(partitionKey));\n\n\t\t\tif (!Is.arrayValue(conditions)) {\n\t\t\t\tconst docRef = collection.doc(id);\n\t\t\t\tconst doc = await docRef.get();\n\n\t\t\t\tif (doc.exists) {\n\t\t\t\t\treturn EntityStorageHelper.unPrepareEntity<T>(doc.data() as T, []);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Use conditions to construct a query\n\t\t\tlet query: Query = collection;\n\n\t\t\tif (secondaryIndex) {\n\t\t\t\tquery = query.where(secondaryIndex as string, \"==\", id);\n\t\t\t} else {\n\t\t\t\t// If no secondaryIndex, include primary key in conditions\n\t\t\t\tquery = query.where(this._primaryKey.property as string, \"==\", id);\n\t\t\t}\n\n\t\t\tif (Is.arrayValue(conditions)) {\n\t\t\t\tfor (const condition of conditions) {\n\t\t\t\t\tquery = query.where(condition.property as string, \"==\", condition.value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst querySnapshot = await query.limit(1).get();\n\t\t\tif (!querySnapshot.empty) {\n\t\t\t\treturn EntityStorageHelper.unPrepareEntity<T>(querySnapshot.docs[0].data() as T, []);\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"getEntityFailed\",\n\t\t\t\t{ id },\n\t\t\t\terr\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Set an entity.\n\t * @param entity The entity to set.\n\t * @param conditions The optional conditions to apply to the update.\n\t * @returns Nothing.\n\t */\n\tpublic async set(entity: T, conditions?: { property: keyof T; value: unknown }[]): Promise<void> {\n\t\tGuards.object(FirestoreEntityStorageConnector.CLASS_NAME, nameof(entity), entity);\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(\n\t\t\tcontextIds,\n\t\t\tthis._partitionContextIds,\n\t\t\tFirestoreEntityStorageConnector._PARTITION_SEPARATOR\n\t\t);\n\n\t\tconst prepared = EntityStorageHelper.prepareEntity(entity, this._entitySchema, undefined, {\n\t\t\tnullBehavior: \"nullify\"\n\t\t});\n\n\t\ttry {\n\t\t\tconst id = prepared[this._primaryKey.property] as string;\n\n\t\t\tconst collection = this._firestoreClient.collection(this.collectionName(partitionKey));\n\n\t\t\tconst docRef = collection.doc(id);\n\n\t\t\tif (!Is.arrayValue(conditions)) {\n\t\t\t\tawait docRef.set(prepared);\n\t\t\t} else {\n\t\t\t\tawait this._firestoreClient.runTransaction(async transaction => {\n\t\t\t\t\tconst docSnapshot = await transaction.get(docRef);\n\n\t\t\t\t\tif (!docSnapshot.exists) {\n\t\t\t\t\t\ttransaction.set(docRef, prepared as object);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst data = docSnapshot.data() as T;\n\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tEntityConditions.check(data, {\n\t\t\t\t\t\t\t\tconditions: conditions.map(c => ({\n\t\t\t\t\t\t\t\t\tproperty: c.property as string,\n\t\t\t\t\t\t\t\t\tcomparison: ComparisonOperator.Equals,\n\t\t\t\t\t\t\t\t\tvalue: c.value\n\t\t\t\t\t\t\t\t}))\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\ttransaction.set(docRef, prepared as object);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"setEntityFailed\",\n\t\t\t\t{ id: entity.id },\n\t\t\t\terr\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Set multiple entities in a batch.\n\t * @param entities The entities to set.\n\t * @returns Nothing.\n\t */\n\tpublic async setBatch(entities: T[]): Promise<void> {\n\t\tGuards.arrayValue(FirestoreEntityStorageConnector.CLASS_NAME, nameof(entities), entities);\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(\n\t\t\tcontextIds,\n\t\t\tthis._partitionContextIds,\n\t\t\tFirestoreEntityStorageConnector._PARTITION_SEPARATOR\n\t\t);\n\n\t\tconst preparedEntities = entities.map(entity =>\n\t\t\tEntityStorageHelper.prepareEntity(entity, this._entitySchema, undefined, {\n\t\t\t\tnullBehavior: \"nullify\"\n\t\t\t})\n\t\t);\n\n\t\ttry {\n\t\t\tconst collection = this._firestoreClient.collection(this.collectionName(partitionKey));\n\t\t\tconst chunkSize = FirestoreEntityStorageConnector._DEFAULT_LIMIT;\n\t\t\tfor (let i = 0; i < preparedEntities.length; i += chunkSize) {\n\t\t\t\tconst chunk = preparedEntities.slice(i, i + chunkSize);\n\t\t\t\tconst batch = this._firestoreClient.batch();\n\t\t\t\tfor (const entity of chunk) {\n\t\t\t\t\tconst id = entity[this._primaryKey.property] as string;\n\t\t\t\t\tconst docRef = collection.doc(id);\n\t\t\t\t\tbatch.set(docRef, entity as { [key: string]: unknown });\n\t\t\t\t}\n\t\t\t\tawait batch.commit();\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"setBatchFailed\",\n\t\t\t\tundefined,\n\t\t\t\terr\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Empty the storage by deleting all entities in the collection.\n\t * @returns Nothing.\n\t */\n\tpublic async empty(): Promise<void> {\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(\n\t\t\tcontextIds,\n\t\t\tthis._partitionContextIds,\n\t\t\tFirestoreEntityStorageConnector._PARTITION_SEPARATOR\n\t\t);\n\n\t\ttry {\n\t\t\tconst collection = this._firestoreClient.collection(this.collectionName(partitionKey));\n\t\t\tconst snapshot = await collection.get();\n\t\t\tconst chunkSize = 500;\n\t\t\tfor (let i = 0; i < snapshot.docs.length; i += chunkSize) {\n\t\t\t\tconst chunk = snapshot.docs.slice(i, i + chunkSize);\n\t\t\t\tconst batch = this._firestoreClient.batch();\n\t\t\t\tfor (const doc of chunk) {\n\t\t\t\t\tbatch.delete(doc.ref);\n\t\t\t\t}\n\t\t\t\tawait batch.commit();\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"emptyFailed\",\n\t\t\t\tundefined,\n\t\t\t\terr\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Remove the entity.\n\t * @param id The id of the entity to remove.\n\t * @param conditions The optional conditions to apply to the delete.\n\t * @returns Nothing.\n\t */\n\tpublic async remove(\n\t\tid: string,\n\t\tconditions?: { property: keyof T; value: unknown }[]\n\t): Promise<void> {\n\t\tGuards.stringValue(FirestoreEntityStorageConnector.CLASS_NAME, nameof(id), id);\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(\n\t\t\tcontextIds,\n\t\t\tthis._partitionContextIds,\n\t\t\tFirestoreEntityStorageConnector._PARTITION_SEPARATOR\n\t\t);\n\n\t\ttry {\n\t\t\tconst collection = this._firestoreClient.collection(this.collectionName(partitionKey));\n\t\t\tconst docRef = collection.doc(id);\n\n\t\t\tif (!Is.arrayValue(conditions)) {\n\t\t\t\tawait docRef.delete();\n\t\t\t} else {\n\t\t\t\tawait this._firestoreClient.runTransaction(async transaction => {\n\t\t\t\t\tconst docSnapshot = await transaction.get(docRef);\n\n\t\t\t\t\tif (docSnapshot.exists) {\n\t\t\t\t\t\tconst data = docSnapshot.data() as T;\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tEntityConditions.check(data, {\n\t\t\t\t\t\t\t\tconditions: conditions.map(c => ({\n\t\t\t\t\t\t\t\t\tproperty: c.property as string,\n\t\t\t\t\t\t\t\t\tcomparison: ComparisonOperator.Equals,\n\t\t\t\t\t\t\t\t\tvalue: c.value\n\t\t\t\t\t\t\t\t}))\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\ttransaction.delete(docRef);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"removeEntityFailed\",\n\t\t\t\t{ id },\n\t\t\t\terr\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Remove multiple entities by their primary key IDs using a Firestore WriteBatch.\n\t * @param ids The ids of the entities to remove.\n\t * @returns Nothing.\n\t */\n\tpublic async removeBatch(ids: string[]): Promise<void> {\n\t\tGuards.arrayValue(FirestoreEntityStorageConnector.CLASS_NAME, nameof(ids), ids);\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(\n\t\t\tcontextIds,\n\t\t\tthis._partitionContextIds,\n\t\t\tFirestoreEntityStorageConnector._PARTITION_SEPARATOR\n\t\t);\n\n\t\ttry {\n\t\t\tconst collection = this._firestoreClient.collection(this.collectionName(partitionKey));\n\t\t\tconst chunkSize = 500;\n\t\t\tfor (let i = 0; i < ids.length; i += chunkSize) {\n\t\t\t\tconst chunk = ids.slice(i, i + chunkSize);\n\t\t\t\tconst batch = this._firestoreClient.batch();\n\t\t\t\tfor (const id of chunk) {\n\t\t\t\t\tconst docRef = collection.doc(id);\n\t\t\t\t\tbatch.delete(docRef);\n\t\t\t\t}\n\t\t\t\tawait batch.commit();\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"removeBatchFailed\",\n\t\t\t\tundefined,\n\t\t\t\terr\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Teardown the storage by deleting all documents across all partition collections.\n\t * @param nodeLoggingComponentType The node logging component type.\n\t * @returns True if the teardown process was successful.\n\t */\n\tpublic async teardown(nodeLoggingComponentType?: string): Promise<boolean> {\n\t\tconst nodeLogging = ComponentFactory.getIfExists<ILoggingComponent>(nodeLoggingComponentType);\n\n\t\tawait nodeLogging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: FirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: \"storeTearingDown\"\n\t\t});\n\n\t\ttry {\n\t\t\tawait this.deleteAllPartitionCollections(this._config.collectionName);\n\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: FirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"storeTornDown\"\n\t\t\t});\n\n\t\t\treturn true;\n\t\t} catch (err) {\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"error\",\n\t\t\t\tsource: FirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"teardownFailed\",\n\t\t\t\terror: BaseError.fromError(err)\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Get a unique list of all the context ids from the storage.\n\t * @returns The list of unique context ids.\n\t */\n\tpublic async getPartitionContextIds(): Promise<IContextIds[]> {\n\t\tconst partitionContextIds = this._partitionContextIds;\n\t\tif (!Is.arrayValue(partitionContextIds)) {\n\t\t\treturn [];\n\t\t}\n\t\ttry {\n\t\t\tconst prefix = `${this._config.collectionName}_`;\n\t\t\tconst collections = await this._firestoreClient.listCollections();\n\t\t\tconst result: IContextIds[] = [];\n\t\t\tfor (const col of collections) {\n\t\t\t\tif (col.id.startsWith(prefix)) {\n\t\t\t\t\tconst partitionKey = col.id.slice(prefix.length);\n\t\t\t\t\tif (Is.stringValue(partitionKey)) {\n\t\t\t\t\t\tresult.push(\n\t\t\t\t\t\t\tContextIdHelper.shortSplit(\n\t\t\t\t\t\t\t\tpartitionContextIds,\n\t\t\t\t\t\t\t\tpartitionKey,\n\t\t\t\t\t\t\t\tFirestoreEntityStorageConnector._PARTITION_SEPARATOR\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn result;\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"getPartitionContextIdsFailed\",\n\t\t\t\tundefined,\n\t\t\t\terr\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Create the target connector for performing the migration using a temporary collection name.\n\t * @param newEntitySchema The name of the new entity schema to create the connector for.\n\t * @returns Connector for performing the migration.\n\t */\n\tpublic async createTargetConnector<U>(\n\t\tnewEntitySchema: string\n\t): Promise<IEntityStorageConnector<U>> {\n\t\tconst migrationCollectionName = `${this._config.collectionName}Migration${Date.now()}`;\n\t\treturn new FirestoreEntityStorageConnector<U>({\n\t\t\tentitySchema: newEntitySchema,\n\t\t\tconfig: { ...this._config, collectionName: migrationCollectionName },\n\t\t\tpartitionContextIds: this._partitionContextIds\n\t\t});\n\t}\n\n\t/**\n\t * Finalize the migration by tearing down the old collections and replacing them with the target collections.\n\t * @param targetConnector The target connector to finalize the migration with.\n\t * @param options The options to control how the migration is finalized.\n\t * @param loggingComponentType The optional component type to use for logging.\n\t * @returns The final connector pointing at the original collection name.\n\t */\n\tpublic async finalizeMigration<U>(\n\t\ttargetConnector: FirestoreEntityStorageConnector<U>,\n\t\toptions?: IMigrationOptions<T, U>,\n\t\tloggingComponentType?: string\n\t): Promise<FirestoreEntityStorageConnector<U>> {\n\t\t// Firestore has no collection-rename operation, so we create fresh collections under\n\t\t// the original name, copy all documents from the migration collections, then delete the\n\t\t// migration collections.\n\n\t\t// Teardown all existing source collections to free up the original collection name prefix.\n\t\tawait this.teardown(loggingComponentType);\n\n\t\t// Create a new connector at the original collection name but with the new schema.\n\t\tconst originalCollectionName = this._config.collectionName;\n\t\tconst finalConnector = new FirestoreEntityStorageConnector<U>({\n\t\t\tentitySchema: targetConnector._entitySchemaName,\n\t\t\tconfig: { ...targetConnector._config, collectionName: originalCollectionName },\n\t\t\tpartitionContextIds: this._partitionContextIds\n\t\t});\n\n\t\tif (await finalConnector.bootstrap(loggingComponentType)) {\n\t\t\t// Since there is no rename, we need to copy the data from the migration table to the new table\n\t\t\tconst partitions = await targetConnector.getPartitionContextIds();\n\t\t\tconst batchSize = options?.batchSize ?? FirestoreEntityStorageConnector._DEFAULT_LIMIT;\n\t\t\tawait this.bulkCopy(targetConnector, finalConnector, partitions, batchSize);\n\n\t\t\tawait targetConnector.teardown(loggingComponentType);\n\n\t\t\treturn finalConnector;\n\t\t}\n\t\tthrow new GeneralError(\n\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\"finalizeMigrationFailedBootstrap\",\n\t\t\tundefined\n\t\t);\n\t}\n\n\t/**\n\t * Cleanup the migration if a migration fails or needs to be aborted.\n\t * @param targetConnector The target connector to cleanup.\n\t * @param options The options to control how the migration is cleaned up.\n\t * @param loggingComponentType The optional component type to use for logging.\n\t */\n\tpublic async cleanupMigration<U>(\n\t\ttargetConnector: IEntityStorageConnector<U> | undefined,\n\t\toptions?: IMigrationOptions<T, U>,\n\t\tloggingComponentType?: string\n\t): Promise<void> {\n\t\t// If something failed the only thing to cleanup is the migration table\n\t\tawait targetConnector?.teardown?.(loggingComponentType);\n\t}\n\n\t/**\n\t * Find all the entities which match the conditions.\n\t * @param conditions The conditions to match for the entities.\n\t * @param sortProperties The optional sort order.\n\t * @param properties The optional properties to return, defaults to all.\n\t * @param cursor The cursor to request the next chunk of entities.\n\t * @param limit The suggested number of entities to return in each chunk.\n\t * @returns The matching entities and a cursor for the next page.\n\t */\n\tpublic async query(\n\t\tconditions?: EntityCondition<T>,\n\t\tsortProperties?: { property: keyof T; sortDirection: SortDirection }[],\n\t\tproperties?: (keyof T)[],\n\t\tcursor?: string,\n\t\tlimit?: number\n\t): Promise<{\n\t\t/**\n\t\t * The entities, which can be partial if a limited keys list was provided.\n\t\t */\n\t\tentities: Partial<T>[];\n\t\t/**\n\t\t * An optional cursor, when defined can be used to call find to get more entities.\n\t\t */\n\t\tcursor?: string;\n\t}> {\n\t\tconst queryDescription: string[] = [];\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(\n\t\t\tcontextIds,\n\t\t\tthis._partitionContextIds,\n\t\t\tFirestoreEntityStorageConnector._PARTITION_SEPARATOR\n\t\t);\n\n\t\tconst finalLimit = limit ?? FirestoreEntityStorageConnector._DEFAULT_LIMIT;\n\n\t\ttry {\n\t\t\tconst collection = this._firestoreClient.collection(this.collectionName(partitionKey));\n\n\t\t\t// Firestore has no native substring search. When any condition needs in-memory\n\t\t\t// filtering (string Includes / NotIncludes), fetch all matching docs and filter\n\t\t\t// client-side, using an index-based cursor for pagination.\n\t\t\tif (!Is.empty(conditions) && this.needsPostFilter(conditions)) {\n\t\t\t\tqueryDescription.push(\"InMemoryFilter\");\n\n\t\t\t\tlet baseQuery = collection as Query;\n\n\t\t\t\tif (Is.arrayValue(sortProperties)) {\n\t\t\t\t\tfor (const { property, sortDirection } of sortProperties) {\n\t\t\t\t\t\tbaseQuery = baseQuery.orderBy(\n\t\t\t\t\t\t\tproperty as string,\n\t\t\t\t\t\t\tsortDirection === SortDirection.Ascending ? \"asc\" : \"desc\"\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst allSnapshot = await baseQuery.get();\n\t\t\t\tlet allEntities = allSnapshot.docs.map((doc: DocumentSnapshot) =>\n\t\t\t\t\tEntityStorageHelper.unPrepareEntity<T>(doc.data() as T, [])\n\t\t\t\t);\n\n\t\t\t\tallEntities = allEntities.filter(e => EntityConditions.check(e as Partial<T>, conditions));\n\n\t\t\t\tlet projected: Partial<T>[];\n\t\t\t\tif (Is.arrayValue(properties)) {\n\t\t\t\t\tprojected = allEntities.map(e => {\n\t\t\t\t\t\tconst out: Partial<T> = {};\n\t\t\t\t\t\tfor (const prop of properties) {\n\t\t\t\t\t\t\tif (prop in (e as object)) {\n\t\t\t\t\t\t\t\tout[prop] = e[prop];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn out;\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tprojected = allEntities;\n\t\t\t\t}\n\n\t\t\t\tconst start = Is.stringValue(cursor) ? Number.parseInt(cursor, 10) : 0;\n\t\t\t\tconst page = projected.slice(start, start + finalLimit);\n\t\t\t\tconst nextCursor =\n\t\t\t\t\tstart + finalLimit < projected.length ? String(start + finalLimit) : undefined;\n\n\t\t\t\treturn { entities: page, cursor: nextCursor };\n\t\t\t}\n\n\t\t\tif (this.hasEmptyInCondition(conditions)) {\n\t\t\t\treturn { entities: [], cursor: undefined };\n\t\t\t}\n\n\t\t\t// Prune empty-In leaves from OR branches: the Firestore SDK throws on\n\t\t\t// Filter.where(prop, \"in\", []) even inside an OR where other branches still match.\n\t\t\t// hasEmptyInCondition above already handles the all-false case, so pruning here\n\t\t\t// is safe — any removed leaf was a no-op branch.\n\t\t\tconst effectiveConditions = !Is.empty(conditions)\n\t\t\t\t? (this.pruneEmptyInConditions(conditions) ?? undefined)\n\t\t\t\t: conditions;\n\n\t\t\tlet query = collection as Query;\n\n\t\t\tif (!Is.empty(effectiveConditions)) {\n\t\t\t\tquery = this.applyConditions(query, effectiveConditions);\n\t\t\t\tqueryDescription.push(`Conditions: ${JSON.stringify(conditions)}`);\n\t\t\t}\n\n\t\t\tif (Is.arrayValue(sortProperties)) {\n\t\t\t\tfor (const { property, sortDirection } of sortProperties) {\n\t\t\t\t\tquery = query.orderBy(\n\t\t\t\t\t\tproperty as string,\n\t\t\t\t\t\tsortDirection === SortDirection.Ascending ? \"asc\" : \"desc\"\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tqueryDescription.push(`Sort: ${JSON.stringify(sortProperties)}`);\n\t\t\t}\n\n\t\t\tif (Is.stringValue(cursor)) {\n\t\t\t\tconst cursorDoc = await this._firestoreClient.doc(cursor).get();\n\t\t\t\tif (cursorDoc?.exists) {\n\t\t\t\t\tquery = query.startAfter(cursorDoc);\n\t\t\t\t}\n\t\t\t\tqueryDescription.push(`Cursor: ${cursor}`);\n\t\t\t}\n\n\t\t\tquery = query.limit(finalLimit + 1);\n\t\t\tqueryDescription.push(`Limit: ${finalLimit}`);\n\n\t\t\tif (Is.arrayValue(properties)) {\n\t\t\t\tquery = query.select(...(properties as string[]));\n\t\t\t\tqueryDescription.push(`Properties: ${properties.join(\", \")}`);\n\t\t\t}\n\n\t\t\tconst querySnapshot = await query.get();\n\t\t\tconst hasMore = querySnapshot.docs.length > finalLimit;\n\t\t\tconst resultDocs = hasMore ? querySnapshot.docs.slice(0, finalLimit) : querySnapshot.docs;\n\t\t\tconst entities = resultDocs.map((doc: DocumentSnapshot) =>\n\t\t\t\tEntityStorageHelper.unPrepareEntity<T>(doc.data() as T, [])\n\t\t\t);\n\n\t\t\tlet nextCursor: string | undefined;\n\t\t\tif (hasMore) {\n\t\t\t\tnextCursor = resultDocs[resultDocs.length - 1].ref.path;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tentities,\n\t\t\t\tcursor: nextCursor\n\t\t\t};\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"queryFailed\",\n\t\t\t\t{ queryDescription: queryDescription.join(\"; \") },\n\t\t\t\terr\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Count all the entities which match the conditions.\n\t * @param conditions The optional conditions to match for the entities.\n\t * @returns The total count of entities in the storage.\n\t */\n\tpublic async count(conditions?: EntityCondition<T>): Promise<number> {\n\t\ttry {\n\t\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\t\tconst partitionKey = ContextIdHelper.combinedContextKey(\n\t\t\t\tcontextIds,\n\t\t\t\tthis._partitionContextIds,\n\t\t\t\tFirestoreEntityStorageConnector._PARTITION_SEPARATOR\n\t\t\t);\n\n\t\t\tconst collection = this._firestoreClient.collection(this.collectionName(partitionKey));\n\n\t\t\tif (this.hasEmptyInCondition(conditions)) {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tif (!Is.empty(conditions) && this.needsPostFilter(conditions)) {\n\t\t\t\tconst allSnapshot = await collection.get();\n\t\t\t\tconst allEntities = allSnapshot.docs.map((doc: DocumentSnapshot) =>\n\t\t\t\t\tEntityStorageHelper.unPrepareEntity<T>(doc.data() as T, [])\n\t\t\t\t);\n\t\t\t\treturn allEntities.filter(e => EntityConditions.check(e as Partial<T>, conditions)).length;\n\t\t\t}\n\n\t\t\tconst effectiveConditions = !Is.empty(conditions)\n\t\t\t\t? (this.pruneEmptyInConditions(conditions) ?? undefined)\n\t\t\t\t: conditions;\n\n\t\t\tlet query = collection as Query;\n\t\t\tif (!Is.empty(effectiveConditions)) {\n\t\t\t\tquery = this.applyConditions(query, effectiveConditions);\n\t\t\t}\n\n\t\t\tconst snapshot = await query.count().get();\n\t\t\treturn snapshot.data().count;\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"countFailed\",\n\t\t\t\tundefined,\n\t\t\t\terr\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Copy all entities from sourceConnector to destConnector, paging through each partition.\n\t * @param sourceConnector The connector to read entities from.\n\t * @param destConnector The connector to write entities to.\n\t * @param partitions The partition list returned by getPartitionContextIds.\n\t * @param batchSize The number of entities to read per page.\n\t * @internal\n\t */\n\tprivate async bulkCopy<U>(\n\t\tsourceConnector: FirestoreEntityStorageConnector<U>,\n\t\tdestConnector: FirestoreEntityStorageConnector<U>,\n\t\tpartitions: IContextIds[],\n\t\tbatchSize: number\n\t): Promise<void> {\n\t\tlet partitionList: IContextIds[];\n\t\tif (Is.arrayValue(partitions)) {\n\t\t\tpartitionList = partitions;\n\t\t} else if (Is.arrayValue(sourceConnector._partitionContextIds)) {\n\t\t\tpartitionList = [];\n\t\t} else {\n\t\t\tpartitionList = [{}];\n\t\t}\n\n\t\tfor (let i = 0; i < partitionList.length; i++) {\n\t\t\tconst partitionKey = ContextIdHelper.combinedContextKey(\n\t\t\t\tpartitionList[i],\n\t\t\t\tsourceConnector._partitionContextIds,\n\t\t\t\tFirestoreEntityStorageConnector._PARTITION_SEPARATOR\n\t\t\t);\n\n\t\t\tconst sourceCollection = sourceConnector._firestoreClient.collection(\n\t\t\t\tsourceConnector.collectionName(partitionKey)\n\t\t\t);\n\t\t\tconst destCollection = destConnector._firestoreClient.collection(\n\t\t\t\tdestConnector.collectionName(partitionKey)\n\t\t\t);\n\n\t\t\tlet lastDoc: DocumentSnapshot | undefined;\n\t\t\tlet hasMore = true;\n\n\t\t\twhile (hasMore) {\n\t\t\t\tlet pageQuery = sourceCollection.limit(batchSize);\n\t\t\t\tif (lastDoc) {\n\t\t\t\t\tpageQuery = pageQuery.startAfter(lastDoc);\n\t\t\t\t}\n\t\t\t\tconst snapshot = await pageQuery.get();\n\t\t\t\tconst docs = snapshot.docs;\n\n\t\t\t\tfor (let j = 0; j < docs.length; j += batchSize) {\n\t\t\t\t\tconst chunk = docs.slice(j, j + batchSize);\n\t\t\t\t\tconst batch = destConnector._firestoreClient.batch();\n\t\t\t\t\tfor (const doc of chunk) {\n\t\t\t\t\t\tbatch.set(destCollection.doc(doc.id), doc.data());\n\t\t\t\t\t}\n\t\t\t\t\tawait batch.commit();\n\t\t\t\t}\n\n\t\t\t\tlastDoc = docs[docs.length - 1];\n\t\t\t\thasMore = docs.length === batchSize;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Delete all documents in every collection whose name starts with collectionName_.\n\t * @param collectionName The base collection name prefix.\n\t * @internal\n\t */\n\tprivate async deleteAllPartitionCollections(collectionName: string): Promise<void> {\n\t\tconst prefix = `${collectionName}_`;\n\t\tconst collections = await this._firestoreClient.listCollections();\n\t\tconst chunkSize = 500;\n\t\tfor (const col of collections) {\n\t\t\tif (col.id.startsWith(prefix)) {\n\t\t\t\tconst snapshot = await col.get();\n\t\t\t\tfor (let i = 0; i < snapshot.docs.length; i += chunkSize) {\n\t\t\t\t\tconst chunk = snapshot.docs.slice(i, i + chunkSize);\n\t\t\t\t\tconst batch = this._firestoreClient.batch();\n\t\t\t\t\tfor (const doc of chunk) {\n\t\t\t\t\t\tbatch.delete(doc.ref);\n\t\t\t\t\t}\n\t\t\t\t\tawait batch.commit();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns true when the condition tree is guaranteed to match nothing due to empty\n\t * In lists, respecting AND/OR boolean semantics (#141):\n\t * - AND group: true if ANY child is always-false (false AND x = false)\n\t * - OR group: true if ALL children are always-false (false OR false = false)\n\t * - Leaf: true only for `In []`\n\t * @param condition The condition tree to inspect.\n\t * @returns True if a short-circuit to empty results is required.\n\t * @internal\n\t */\n\tprivate hasEmptyInCondition(condition?: EntityCondition<T>): boolean {\n\t\tif (Is.empty(condition)) {\n\t\t\treturn false;\n\t\t}\n\t\tif (\"conditions\" in condition) {\n\t\t\treturn condition.logicalOperator === LogicalOperator.Or\n\t\t\t\t? condition.conditions.every(c => this.hasEmptyInCondition(c))\n\t\t\t\t: condition.conditions.some(c => this.hasEmptyInCondition(c));\n\t\t}\n\t\treturn (\n\t\t\tcondition.comparison === ComparisonOperator.In &&\n\t\t\tIs.array(condition.value) &&\n\t\t\tcondition.value.length === 0\n\t\t);\n\t}\n\n\t/**\n\t * Returns a copy of the condition tree with all empty-In leaves removed.\n\t * Used to keep `In []` out of native Firestore Filter calls (the SDK throws on\n\t * `Filter.where(prop, \"in\", [])`) while preserving correct OR semantics (#141).\n\t * Returns null when the entire subtree reduces to nothing (caller should treat\n\t * as no conditions).\n\t * @param condition The condition to prune.\n\t * @returns The pruned condition, or null if the subtree was fully removed.\n\t * @internal\n\t */\n\tprivate pruneEmptyInConditions(condition: EntityCondition<T>): EntityCondition<T> | null {\n\t\tif (!(\"conditions\" in condition)) {\n\t\t\tif (\n\t\t\t\tcondition.comparison === ComparisonOperator.In &&\n\t\t\t\tIs.array(condition.value) &&\n\t\t\t\tcondition.value.length === 0\n\t\t\t) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn condition;\n\t\t}\n\t\t// For AND groups: if any child has an empty In, the whole AND is dead.\n\t\t// Do not recurse — promoting the surviving siblings would turn a dead\n\t\t// branch into a live one when this AND sits inside an OR (#141).\n\t\tif (condition.logicalOperator !== LogicalOperator.Or && this.hasEmptyInCondition(condition)) {\n\t\t\treturn null;\n\t\t}\n\t\t// For OR groups: prune dead branches individually so the Firestore SDK\n\t\t// never receives `In []`, while keeping live siblings.\n\t\tconst pruned = condition.conditions\n\t\t\t.map(c => this.pruneEmptyInConditions(c))\n\t\t\t.filter((c): c is EntityCondition<T> => c !== null);\n\t\tif (pruned.length === 0) {\n\t\t\treturn null;\n\t\t}\n\t\tif (pruned.length === 1) {\n\t\t\treturn pruned[0];\n\t\t}\n\t\treturn { ...condition, conditions: pruned };\n\t}\n\n\t/**\n\t * Returns true when any leaf condition requires client-side filtering\n\t * (Firestore has no native string-contains / not-contains operator).\n\t * @param condition The condition tree to inspect.\n\t * @returns True if post-filtering is required.\n\t * @internal\n\t */\n\tprivate needsPostFilter(condition?: EntityCondition<T>): boolean {\n\t\tif (Is.empty(condition)) {\n\t\t\treturn false;\n\t\t}\n\t\tif (\"conditions\" in condition) {\n\t\t\treturn condition.conditions.some(c => this.needsPostFilter(c));\n\t\t}\n\t\tconst { comparison, value } = condition;\n\t\tif (comparison === ComparisonOperator.NotIncludes) {\n\t\t\treturn true;\n\t\t}\n\t\t// Includes on a primitive (string/number) means substring search — not natively supported.\n\t\t// Includes on an object means array-contains, which Firestore does support.\n\t\tif (\n\t\t\tcomparison === ComparisonOperator.Includes &&\n\t\t\t(value === null || typeof value !== \"object\")\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Apply conditions to a Firestore query using composite Filter objects so that\n\t * OR groups are handled correctly.\n\t * @param query The initial query.\n\t * @param condition The condition to apply.\n\t * @returns The updated query.\n\t * @internal\n\t */\n\tprivate applyConditions(query: Query, condition: EntityCondition<T>): Query {\n\t\treturn query.where(this.buildFilter(condition));\n\t}\n\n\t/**\n\t * Recursively convert an EntityCondition tree into a Firestore Filter.\n\t * Only called for native conditions (needsPostFilter must be false).\n\t * @param condition The condition to convert.\n\t * @returns A Firestore Filter.\n\t * @throws GeneralError if the comparison operator is not supported.\n\t * @internal\n\t */\n\tprivate buildFilter(condition: EntityCondition<T>): Filter {\n\t\tif (\"conditions\" in condition) {\n\t\t\tconst filters = condition.conditions.map(c => this.buildFilter(c));\n\t\t\treturn condition.logicalOperator === LogicalOperator.Or\n\t\t\t\t? Filter.or(...filters)\n\t\t\t\t: Filter.and(...filters);\n\t\t}\n\t\tconst { property, comparison } = condition;\n\t\t// Firestore has no undefined type — null has the correct semantics:\n\t\t// == null matches documents where the field is null OR missing\n\t\t// != null matches documents where the field exists and is not null\n\t\tconst value = condition.value === undefined ? null : condition.value;\n\t\tswitch (comparison) {\n\t\t\tcase ComparisonOperator.Equals:\n\t\t\t\treturn Filter.where(property, \"==\", value);\n\t\t\tcase ComparisonOperator.NotEquals:\n\t\t\t\treturn Filter.where(property, \"!=\", value);\n\t\t\tcase ComparisonOperator.GreaterThan:\n\t\t\t\treturn Filter.where(property, \">\", value);\n\t\t\tcase ComparisonOperator.LessThan:\n\t\t\t\treturn Filter.where(property, \"<\", value);\n\t\t\tcase ComparisonOperator.GreaterThanOrEqual:\n\t\t\t\treturn Filter.where(property, \">=\", value);\n\t\t\tcase ComparisonOperator.LessThanOrEqual:\n\t\t\t\treturn Filter.where(property, \"<=\", value);\n\t\t\tcase ComparisonOperator.In:\n\t\t\t\treturn Filter.where(property, \"in\", value);\n\t\t\tcase ComparisonOperator.Includes:\n\t\t\t\t// Object value → array-contains (caller ensured needsPostFilter is false here)\n\t\t\t\treturn Filter.where(property, \"array-contains\", value);\n\t\t\tcase ComparisonOperator.NotIncludes:\n\t\t\tdefault:\n\t\t\t\tthrow new GeneralError(\n\t\t\t\t\tFirestoreEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\t\"unsupportedComparisonOperator\",\n\t\t\t\t\t{ comparison }\n\t\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Get the collection name based on partition key.\n\t * @param partitionKey The optional partition key to include in the collection name.\n\t * @returns The collection name.\n\t * @internal\n\t */\n\tprivate collectionName(partitionKey?: string): string {\n\t\treturn `${this._config.collectionName}_${partitionKey ?? \"default\"}`;\n\t}\n}\n"]}
package/docs/changelog.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.0.3-next.22](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-gcp-firestore-v0.0.3-next.21...entity-storage-connector-gcp-firestore-v0.0.3-next.22) (2026-06-08)
4
+
5
+
6
+ ### Features
7
+
8
+ * add ISchemaMigration chain, SchemaVersionMigrator runner and version store ([#110](https://github.com/iotaledger/twin-entity-storage/issues/110)) ([2dac924](https://github.com/iotaledger/twin-entity-storage/commit/2dac9244a752cb58304d1649ff03c3a2469783dd))
9
+
10
+
11
+ ### Dependencies
12
+
13
+ * The following workspace dependencies were updated
14
+ * dependencies
15
+ * @twin.org/entity-storage-models bumped from 0.0.3-next.21 to 0.0.3-next.22
16
+ * devDependencies
17
+ * @twin.org/entity-storage-connector-memory bumped from 0.0.3-next.21 to 0.0.3-next.22
18
+
3
19
  ## [0.0.3-next.21](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-gcp-firestore-v0.0.3-next.20...entity-storage-connector-gcp-firestore-v0.0.3-next.21) (2026-06-01)
4
20
 
5
21
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twin.org/entity-storage-connector-gcp-firestore",
3
- "version": "0.0.3-next.21",
3
+ "version": "0.0.3-next.22",
4
4
  "description": "Google Cloud Firestore connector for document-based persistence.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -18,7 +18,7 @@
18
18
  "@twin.org/context": "next",
19
19
  "@twin.org/core": "next",
20
20
  "@twin.org/entity": "next",
21
- "@twin.org/entity-storage-models": "0.0.3-next.21",
21
+ "@twin.org/entity-storage-models": "0.0.3-next.22",
22
22
  "@twin.org/logging-models": "next",
23
23
  "@twin.org/nameof": "next"
24
24
  },