@enbox/dwn-sdk-js 0.0.6 → 0.0.8
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.
- package/dist/browser.mjs +8 -8
- package/dist/browser.mjs.map +4 -4
- package/dist/esm/generated/precompiled-validators.js +762 -911
- package/dist/esm/generated/precompiled-validators.js.map +1 -1
- package/dist/esm/src/core/abstract-message.js +4 -0
- package/dist/esm/src/core/abstract-message.js.map +1 -1
- package/dist/esm/src/core/auth.js +22 -33
- package/dist/esm/src/core/auth.js.map +1 -1
- package/dist/esm/src/core/constants.js +11 -0
- package/dist/esm/src/core/constants.js.map +1 -0
- package/dist/esm/src/core/core-protocol.js +44 -0
- package/dist/esm/src/core/core-protocol.js.map +1 -0
- package/dist/esm/src/core/dwn-constant.js +7 -7
- package/dist/esm/src/core/dwn-constant.js.map +1 -1
- package/dist/esm/src/core/dwn-error.js +10 -12
- package/dist/esm/src/core/dwn-error.js.map +1 -1
- package/dist/esm/src/core/grant-authorization.js +50 -52
- package/dist/esm/src/core/grant-authorization.js.map +1 -1
- package/dist/esm/src/core/message.js +85 -116
- package/dist/esm/src/core/message.js.map +1 -1
- package/dist/esm/src/core/messages-grant-authorization.js +63 -78
- package/dist/esm/src/core/messages-grant-authorization.js.map +1 -1
- package/dist/esm/src/core/protocol-authorization-action.js +266 -0
- package/dist/esm/src/core/protocol-authorization-action.js.map +1 -0
- package/dist/esm/src/core/protocol-authorization-validation.js +321 -0
- package/dist/esm/src/core/protocol-authorization-validation.js.map +1 -0
- package/dist/esm/src/core/protocol-authorization.js +144 -741
- package/dist/esm/src/core/protocol-authorization.js.map +1 -1
- package/dist/esm/src/core/protocols-grant-authorization.js +24 -38
- package/dist/esm/src/core/protocols-grant-authorization.js.map +1 -1
- package/dist/esm/src/core/record-chain.js +64 -0
- package/dist/esm/src/core/record-chain.js.map +1 -0
- package/dist/esm/src/core/records-grant-authorization.js +53 -72
- package/dist/esm/src/core/records-grant-authorization.js.map +1 -1
- package/dist/esm/src/core/resumable-task-manager.js +50 -65
- package/dist/esm/src/core/resumable-task-manager.js.map +1 -1
- package/dist/esm/src/core/tenant-gate.js +2 -13
- package/dist/esm/src/core/tenant-gate.js.map +1 -1
- package/dist/esm/src/dwn.js +108 -101
- package/dist/esm/src/dwn.js.map +1 -1
- package/dist/esm/src/event-stream/event-emitter-event-log.js +204 -0
- package/dist/esm/src/event-stream/event-emitter-event-log.js.map +1 -0
- package/dist/esm/src/handlers/messages-read.js +67 -81
- package/dist/esm/src/handlers/messages-read.js.map +1 -1
- package/dist/esm/src/handlers/messages-subscribe.js +51 -63
- package/dist/esm/src/handlers/messages-subscribe.js.map +1 -1
- package/dist/esm/src/handlers/messages-sync.js +75 -89
- package/dist/esm/src/handlers/messages-sync.js.map +1 -1
- package/dist/esm/src/handlers/protocols-configure.js +153 -163
- package/dist/esm/src/handlers/protocols-configure.js.map +1 -1
- package/dist/esm/src/handlers/protocols-query.js +52 -55
- package/dist/esm/src/handlers/protocols-query.js.map +1 -1
- package/dist/esm/src/handlers/records-count.js +97 -85
- package/dist/esm/src/handlers/records-count.js.map +1 -1
- package/dist/esm/src/handlers/records-delete.js +75 -93
- package/dist/esm/src/handlers/records-delete.js.map +1 -1
- package/dist/esm/src/handlers/records-query.js +116 -105
- package/dist/esm/src/handlers/records-query.js.map +1 -1
- package/dist/esm/src/handlers/records-read.js +130 -132
- package/dist/esm/src/handlers/records-read.js.map +1 -1
- package/dist/esm/src/handlers/records-subscribe.js +164 -104
- package/dist/esm/src/handlers/records-subscribe.js.map +1 -1
- package/dist/esm/src/handlers/records-write.js +213 -280
- package/dist/esm/src/handlers/records-write.js.map +1 -1
- package/dist/esm/src/index.js +5 -2
- package/dist/esm/src/index.js.map +1 -1
- package/dist/esm/src/interfaces/messages-read.js +24 -32
- package/dist/esm/src/interfaces/messages-read.js.map +1 -1
- package/dist/esm/src/interfaces/messages-subscribe.js +28 -41
- package/dist/esm/src/interfaces/messages-subscribe.js.map +1 -1
- package/dist/esm/src/interfaces/messages-sync.js +26 -40
- package/dist/esm/src/interfaces/messages-sync.js.map +1 -1
- package/dist/esm/src/interfaces/protocols-configure.js +87 -65
- package/dist/esm/src/interfaces/protocols-configure.js.map +1 -1
- package/dist/esm/src/interfaces/protocols-query.js +55 -68
- package/dist/esm/src/interfaces/protocols-query.js.map +1 -1
- package/dist/esm/src/interfaces/records-count.js +50 -66
- package/dist/esm/src/interfaces/records-count.js.map +1 -1
- package/dist/esm/src/interfaces/records-delete.js +45 -55
- package/dist/esm/src/interfaces/records-delete.js.map +1 -1
- package/dist/esm/src/interfaces/records-query.js +60 -76
- package/dist/esm/src/interfaces/records-query.js.map +1 -1
- package/dist/esm/src/interfaces/records-read.js +51 -67
- package/dist/esm/src/interfaces/records-read.js.map +1 -1
- package/dist/esm/src/interfaces/records-subscribe.js +53 -68
- package/dist/esm/src/interfaces/records-subscribe.js.map +1 -1
- package/dist/esm/src/interfaces/records-write-query.js +102 -0
- package/dist/esm/src/interfaces/records-write-query.js.map +1 -0
- package/dist/esm/src/interfaces/records-write-signing.js +81 -0
- package/dist/esm/src/interfaces/records-write-signing.js.map +1 -0
- package/dist/esm/src/interfaces/records-write.js +396 -610
- package/dist/esm/src/interfaces/records-write.js.map +1 -1
- package/dist/esm/src/jose/algorithms/signing/ed25519.js +10 -19
- package/dist/esm/src/jose/algorithms/signing/ed25519.js.map +1 -1
- package/dist/esm/src/jose/jws/general/builder.js +23 -35
- package/dist/esm/src/jose/jws/general/builder.js.map +1 -1
- package/dist/esm/src/jose/jws/general/verifier.js +56 -69
- package/dist/esm/src/jose/jws/general/verifier.js.map +1 -1
- package/dist/esm/src/protocols/permission-grant.js +43 -14
- package/dist/esm/src/protocols/permission-grant.js.map +1 -1
- package/dist/esm/src/protocols/permission-request.js +28 -14
- package/dist/esm/src/protocols/permission-request.js.map +1 -1
- package/dist/esm/src/protocols/permissions.js +325 -227
- package/dist/esm/src/protocols/permissions.js.map +1 -1
- package/dist/esm/src/smt/smt-store-level.js +42 -64
- package/dist/esm/src/smt/smt-store-level.js.map +1 -1
- package/dist/esm/src/smt/smt-store-memory.js +19 -45
- package/dist/esm/src/smt/smt-store-memory.js.map +1 -1
- package/dist/esm/src/smt/smt-utils.js +28 -45
- package/dist/esm/src/smt/smt-utils.js.map +1 -1
- package/dist/esm/src/smt/sparse-merkle-tree.js +426 -471
- package/dist/esm/src/smt/sparse-merkle-tree.js.map +1 -1
- package/dist/esm/src/state-index/state-index-level.js +113 -150
- package/dist/esm/src/state-index/state-index-level.js.map +1 -1
- package/dist/esm/src/store/blockstore-level.js +54 -156
- package/dist/esm/src/store/blockstore-level.js.map +1 -1
- package/dist/esm/src/store/blockstore-mock.js +48 -153
- package/dist/esm/src/store/blockstore-mock.js.map +1 -1
- package/dist/esm/src/store/data-store-level.js +137 -100
- package/dist/esm/src/store/data-store-level.js.map +1 -1
- package/dist/esm/src/store/index-level-compound.js +246 -0
- package/dist/esm/src/store/index-level-compound.js.map +1 -0
- package/dist/esm/src/store/index-level.js +307 -715
- package/dist/esm/src/store/index-level.js.map +1 -1
- package/dist/esm/src/store/level-wrapper.js +143 -244
- package/dist/esm/src/store/level-wrapper.js.map +1 -1
- package/dist/esm/src/store/message-store-level.js +71 -94
- package/dist/esm/src/store/message-store-level.js.map +1 -1
- package/dist/esm/src/store/resumable-task-store-level.js +62 -101
- package/dist/esm/src/store/resumable-task-store-level.js.map +1 -1
- package/dist/esm/src/store/storage-controller.js +131 -146
- package/dist/esm/src/store/storage-controller.js.map +1 -1
- package/dist/esm/src/types/permission-types.js.map +1 -1
- package/dist/esm/src/types/protocols-types.js +10 -0
- package/dist/esm/src/types/protocols-types.js.map +1 -1
- package/dist/esm/src/types/records-types.js.map +1 -1
- package/dist/esm/src/utils/abort.js +8 -19
- package/dist/esm/src/utils/abort.js.map +1 -1
- package/dist/esm/src/utils/array.js +15 -49
- package/dist/esm/src/utils/array.js.map +1 -1
- package/dist/esm/src/utils/cid.js +29 -77
- package/dist/esm/src/utils/cid.js.map +1 -1
- package/dist/esm/src/utils/data-stream.js +37 -65
- package/dist/esm/src/utils/data-stream.js.map +1 -1
- package/dist/esm/src/utils/encryption.js +136 -162
- package/dist/esm/src/utils/encryption.js.map +1 -1
- package/dist/esm/src/utils/filter.js +1 -12
- package/dist/esm/src/utils/filter.js.map +1 -1
- package/dist/esm/src/utils/hd-key.js +45 -71
- package/dist/esm/src/utils/hd-key.js.map +1 -1
- package/dist/esm/src/utils/jws.js +9 -20
- package/dist/esm/src/utils/jws.js.map +1 -1
- package/dist/esm/src/utils/memory-cache.js +12 -23
- package/dist/esm/src/utils/memory-cache.js.map +1 -1
- package/dist/esm/src/utils/messages.js +21 -33
- package/dist/esm/src/utils/messages.js.map +1 -1
- package/dist/esm/src/utils/private-key-signer.js +9 -17
- package/dist/esm/src/utils/private-key-signer.js.map +1 -1
- package/dist/esm/src/utils/protocols.js +62 -70
- package/dist/esm/src/utils/protocols.js.map +1 -1
- package/dist/esm/src/utils/records.js +103 -166
- package/dist/esm/src/utils/records.js.map +1 -1
- package/dist/esm/src/utils/secp256k1.js +60 -96
- package/dist/esm/src/utils/secp256k1.js.map +1 -1
- package/dist/esm/src/utils/secp256r1.js +54 -71
- package/dist/esm/src/utils/secp256r1.js.map +1 -1
- package/dist/esm/src/utils/time.js +5 -18
- package/dist/esm/src/utils/time.js.map +1 -1
- package/dist/esm/src/utils/url.js +3 -3
- package/dist/esm/src/utils/url.js.map +1 -1
- package/dist/esm/tests/core/auth.spec.js +3 -12
- package/dist/esm/tests/core/auth.spec.js.map +1 -1
- package/dist/esm/tests/core/message.spec.js +50 -59
- package/dist/esm/tests/core/message.spec.js.map +1 -1
- package/dist/esm/tests/core/protocol-authorization.spec.js +10 -18
- package/dist/esm/tests/core/protocol-authorization.spec.js.map +1 -1
- package/dist/esm/tests/dwn.spec.js +65 -89
- package/dist/esm/tests/dwn.spec.js.map +1 -1
- package/dist/esm/tests/event-emitter-event-log.spec.js +305 -0
- package/dist/esm/tests/event-emitter-event-log.spec.js.map +1 -0
- package/dist/esm/tests/features/author-delegated-grant.spec.js +337 -347
- package/dist/esm/tests/features/author-delegated-grant.spec.js.map +1 -1
- package/dist/esm/tests/features/owner-delegated-grant.spec.js +160 -172
- package/dist/esm/tests/features/owner-delegated-grant.spec.js.map +1 -1
- package/dist/esm/tests/features/owner-signature.spec.js +78 -82
- package/dist/esm/tests/features/owner-signature.spec.js.map +1 -1
- package/dist/esm/tests/features/permissions.spec.js +449 -184
- package/dist/esm/tests/features/permissions.spec.js.map +1 -1
- package/dist/esm/tests/features/protocol-composition.spec.js +981 -360
- package/dist/esm/tests/features/protocol-composition.spec.js.map +1 -1
- package/dist/esm/tests/features/protocol-create-action.spec.js +45 -54
- package/dist/esm/tests/features/protocol-create-action.spec.js.map +1 -1
- package/dist/esm/tests/features/protocol-delete-action.spec.js +99 -108
- package/dist/esm/tests/features/protocol-delete-action.spec.js.map +1 -1
- package/dist/esm/tests/features/protocol-update-action.spec.js +108 -117
- package/dist/esm/tests/features/protocol-update-action.spec.js.map +1 -1
- package/dist/esm/tests/features/records-immutable.spec.js +315 -0
- package/dist/esm/tests/features/records-immutable.spec.js.map +1 -0
- package/dist/esm/tests/features/records-prune.spec.js +178 -194
- package/dist/esm/tests/features/records-prune.spec.js.map +1 -1
- package/dist/esm/tests/features/records-record-limit.spec.js +542 -0
- package/dist/esm/tests/features/records-record-limit.spec.js.map +1 -0
- package/dist/esm/tests/features/records-tags.spec.js +456 -463
- package/dist/esm/tests/features/records-tags.spec.js.map +1 -1
- package/dist/esm/tests/features/resumable-tasks.spec.js +88 -98
- package/dist/esm/tests/features/resumable-tasks.spec.js.map +1 -1
- package/dist/esm/tests/handlers/messages-read.spec.js +215 -210
- package/dist/esm/tests/handlers/messages-read.spec.js.map +1 -1
- package/dist/esm/tests/handlers/messages-subscribe.spec.js +309 -171
- package/dist/esm/tests/handlers/messages-subscribe.spec.js.map +1 -1
- package/dist/esm/tests/handlers/messages-sync.spec.js +272 -199
- package/dist/esm/tests/handlers/messages-sync.spec.js.map +1 -1
- package/dist/esm/tests/handlers/protocols-configure.spec.js +247 -241
- package/dist/esm/tests/handlers/protocols-configure.spec.js.map +1 -1
- package/dist/esm/tests/handlers/protocols-query.spec.js +159 -172
- package/dist/esm/tests/handlers/protocols-query.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-count.spec.js +101 -105
- package/dist/esm/tests/handlers/records-count.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-delete.spec.js +266 -279
- package/dist/esm/tests/handlers/records-delete.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-query.spec.js +984 -996
- package/dist/esm/tests/handlers/records-query.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-read.spec.js +542 -671
- package/dist/esm/tests/handlers/records-read.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-subscribe.spec.js +433 -302
- package/dist/esm/tests/handlers/records-subscribe.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-write.spec.js +1216 -1140
- package/dist/esm/tests/handlers/records-write.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/messages-get.spec.js +39 -48
- package/dist/esm/tests/interfaces/messages-get.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/messages-subscribe.spec.js +4 -13
- package/dist/esm/tests/interfaces/messages-subscribe.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/protocols-configure.spec.js +212 -88
- package/dist/esm/tests/interfaces/protocols-configure.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/protocols-query.spec.js +8 -17
- package/dist/esm/tests/interfaces/protocols-query.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/records-delete.spec.js +8 -17
- package/dist/esm/tests/interfaces/records-delete.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/records-query.spec.js +20 -29
- package/dist/esm/tests/interfaces/records-query.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/records-read.spec.js +42 -51
- package/dist/esm/tests/interfaces/records-read.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/records-subscribe.spec.js +16 -25
- package/dist/esm/tests/interfaces/records-subscribe.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/records-write.spec.js +190 -219
- package/dist/esm/tests/interfaces/records-write.spec.js.map +1 -1
- package/dist/esm/tests/jose/jws/general.spec.js +36 -45
- package/dist/esm/tests/jose/jws/general.spec.js.map +1 -1
- package/dist/esm/tests/protocols/permission-grant.spec.js +44 -50
- package/dist/esm/tests/protocols/permission-grant.spec.js.map +1 -1
- package/dist/esm/tests/protocols/permission-request.spec.js +23 -32
- package/dist/esm/tests/protocols/permission-request.spec.js.map +1 -1
- package/dist/esm/tests/protocols/permissions.spec.js +49 -55
- package/dist/esm/tests/protocols/permissions.spec.js.map +1 -1
- package/dist/esm/tests/scenarios/aggregator.spec.js +127 -138
- package/dist/esm/tests/scenarios/aggregator.spec.js.map +1 -1
- package/dist/esm/tests/scenarios/deleted-record.spec.js +372 -36
- package/dist/esm/tests/scenarios/deleted-record.spec.js.map +1 -1
- package/dist/esm/tests/scenarios/end-to-end-tests.spec.js +55 -64
- package/dist/esm/tests/scenarios/end-to-end-tests.spec.js.map +1 -1
- package/dist/esm/tests/scenarios/nested-roles.spec.js +66 -76
- package/dist/esm/tests/scenarios/nested-roles.spec.js.map +1 -1
- package/dist/esm/tests/scenarios/subscriptions.spec.js +451 -354
- package/dist/esm/tests/scenarios/subscriptions.spec.js.map +1 -1
- package/dist/esm/tests/smt/smt-store-level.spec.js +76 -87
- package/dist/esm/tests/smt/smt-store-level.spec.js.map +1 -1
- package/dist/esm/tests/smt/sparse-merkle-tree.spec.js +344 -353
- package/dist/esm/tests/smt/sparse-merkle-tree.spec.js.map +1 -1
- package/dist/esm/tests/state-index/state-index-level.spec.js +117 -126
- package/dist/esm/tests/state-index/state-index-level.spec.js.map +1 -1
- package/dist/esm/tests/store/blockstore-level.spec.js +44 -99
- package/dist/esm/tests/store/blockstore-level.spec.js.map +1 -1
- package/dist/esm/tests/store/blockstore-mock.spec.js +40 -120
- package/dist/esm/tests/store/blockstore-mock.spec.js.map +1 -1
- package/dist/esm/tests/store/data-store-level.spec.js +160 -108
- package/dist/esm/tests/store/data-store-level.spec.js.map +1 -1
- package/dist/esm/tests/store/index-level.spec.js +404 -414
- package/dist/esm/tests/store/index-level.spec.js.map +1 -1
- package/dist/esm/tests/store/message-store-level.spec.js +13 -22
- package/dist/esm/tests/store/message-store-level.spec.js.map +1 -1
- package/dist/esm/tests/store/message-store.spec.js +229 -238
- package/dist/esm/tests/store/message-store.spec.js.map +1 -1
- package/dist/esm/tests/test-event-stream.js +12 -13
- package/dist/esm/tests/test-event-stream.js.map +1 -1
- package/dist/esm/tests/test-stores.js +16 -13
- package/dist/esm/tests/test-stores.js.map +1 -1
- package/dist/esm/tests/test-suite.js +8 -15
- package/dist/esm/tests/test-suite.js.map +1 -1
- package/dist/esm/tests/utils/cid.spec.js +24 -33
- package/dist/esm/tests/utils/cid.spec.js.map +1 -1
- package/dist/esm/tests/utils/data-stream.spec.js +48 -57
- package/dist/esm/tests/utils/data-stream.spec.js.map +1 -1
- package/dist/esm/tests/utils/encryption-callbacks.spec.js +45 -54
- package/dist/esm/tests/utils/encryption-callbacks.spec.js.map +1 -1
- package/dist/esm/tests/utils/encryption.spec.js +229 -82
- package/dist/esm/tests/utils/encryption.spec.js.map +1 -1
- package/dist/esm/tests/utils/filters.spec.js +46 -55
- package/dist/esm/tests/utils/filters.spec.js.map +1 -1
- package/dist/esm/tests/utils/hd-key.spec.js +10 -19
- package/dist/esm/tests/utils/hd-key.spec.js.map +1 -1
- package/dist/esm/tests/utils/jws.spec.js +3 -12
- package/dist/esm/tests/utils/jws.spec.js.map +1 -1
- package/dist/esm/tests/utils/memory-cache.spec.js +9 -18
- package/dist/esm/tests/utils/memory-cache.spec.js.map +1 -1
- package/dist/esm/tests/utils/messages.spec.js +18 -20
- package/dist/esm/tests/utils/messages.spec.js.map +1 -1
- package/dist/esm/tests/utils/poller.js +22 -33
- package/dist/esm/tests/utils/poller.js.map +1 -1
- package/dist/esm/tests/utils/private-key-signer.spec.js +15 -24
- package/dist/esm/tests/utils/private-key-signer.spec.js.map +1 -1
- package/dist/esm/tests/utils/records.spec.js +14 -27
- package/dist/esm/tests/utils/records.spec.js.map +1 -1
- package/dist/esm/tests/utils/secp256k1.spec.js +16 -25
- package/dist/esm/tests/utils/secp256k1.spec.js.map +1 -1
- package/dist/esm/tests/utils/secp256r1.spec.js +18 -27
- package/dist/esm/tests/utils/secp256r1.spec.js.map +1 -1
- package/dist/esm/tests/utils/test-data-generator.js +446 -467
- package/dist/esm/tests/utils/test-data-generator.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/definitions.spec.js +2 -11
- package/dist/esm/tests/validation/json-schemas/definitions.spec.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/jwk/general-jwk.spec.js +4 -13
- package/dist/esm/tests/validation/json-schemas/jwk/general-jwk.spec.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/jwk/public-jwk.spec.js +8 -17
- package/dist/esm/tests/validation/json-schemas/jwk/public-jwk.spec.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/jwk-verification-method.spec.js +3 -12
- package/dist/esm/tests/validation/json-schemas/jwk-verification-method.spec.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/protocols/protocols-configure.spec.js +4 -13
- package/dist/esm/tests/validation/json-schemas/protocols/protocols-configure.spec.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/records/records-query.spec.js +2 -11
- package/dist/esm/tests/validation/json-schemas/records/records-query.spec.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/records/records-read.spec.js +2 -11
- package/dist/esm/tests/validation/json-schemas/records/records-read.spec.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/records/records-write.spec.js +44 -24
- package/dist/esm/tests/validation/json-schemas/records/records-write.spec.js.map +1 -1
- package/dist/types/generated/precompiled-validators.d.ts +49 -40
- package/dist/types/generated/precompiled-validators.d.ts.map +1 -1
- package/dist/types/src/core/constants.d.ts +11 -0
- package/dist/types/src/core/constants.d.ts.map +1 -0
- package/dist/types/src/core/core-protocol.d.ts +89 -0
- package/dist/types/src/core/core-protocol.d.ts.map +1 -0
- package/dist/types/src/core/dwn-error.d.ts +9 -12
- package/dist/types/src/core/dwn-error.d.ts.map +1 -1
- package/dist/types/src/core/grant-authorization.d.ts +6 -2
- package/dist/types/src/core/grant-authorization.d.ts.map +1 -1
- package/dist/types/src/core/protocol-authorization-action.d.ts +42 -0
- package/dist/types/src/core/protocol-authorization-action.d.ts.map +1 -0
- package/dist/types/src/core/protocol-authorization-validation.d.ts +81 -0
- package/dist/types/src/core/protocol-authorization-validation.d.ts.map +1 -0
- package/dist/types/src/core/protocol-authorization.d.ts +24 -106
- package/dist/types/src/core/protocol-authorization.d.ts.map +1 -1
- package/dist/types/src/core/record-chain.d.ts +24 -0
- package/dist/types/src/core/record-chain.d.ts.map +1 -0
- package/dist/types/src/core/records-grant-authorization.d.ts.map +1 -1
- package/dist/types/src/dwn.d.ts +19 -7
- package/dist/types/src/dwn.d.ts.map +1 -1
- package/dist/types/src/event-stream/event-emitter-event-log.d.ts +50 -0
- package/dist/types/src/event-stream/event-emitter-event-log.d.ts.map +1 -0
- package/dist/types/src/handlers/messages-read.d.ts +3 -8
- package/dist/types/src/handlers/messages-read.d.ts.map +1 -1
- package/dist/types/src/handlers/messages-subscribe.d.ts +6 -10
- package/dist/types/src/handlers/messages-subscribe.d.ts.map +1 -1
- package/dist/types/src/handlers/messages-sync.d.ts +3 -8
- package/dist/types/src/handlers/messages-sync.d.ts.map +1 -1
- package/dist/types/src/handlers/protocols-configure.d.ts +3 -10
- package/dist/types/src/handlers/protocols-configure.d.ts.map +1 -1
- package/dist/types/src/handlers/protocols-query.d.ts +3 -8
- package/dist/types/src/handlers/protocols-query.d.ts.map +1 -1
- package/dist/types/src/handlers/records-count.d.ts +3 -6
- package/dist/types/src/handlers/records-count.d.ts.map +1 -1
- package/dist/types/src/handlers/records-delete.d.ts +3 -8
- package/dist/types/src/handlers/records-delete.d.ts.map +1 -1
- package/dist/types/src/handlers/records-query.d.ts +3 -8
- package/dist/types/src/handlers/records-query.d.ts.map +1 -1
- package/dist/types/src/handlers/records-read.d.ts +3 -8
- package/dist/types/src/handlers/records-read.d.ts.map +1 -1
- package/dist/types/src/handlers/records-subscribe.d.ts +8 -10
- package/dist/types/src/handlers/records-subscribe.d.ts.map +1 -1
- package/dist/types/src/handlers/records-write.d.ts +4 -24
- package/dist/types/src/handlers/records-write.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +8 -4
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/interfaces/messages-subscribe.d.ts +5 -0
- package/dist/types/src/interfaces/messages-subscribe.d.ts.map +1 -1
- package/dist/types/src/interfaces/protocols-configure.d.ts.map +1 -1
- package/dist/types/src/interfaces/records-subscribe.d.ts +5 -0
- package/dist/types/src/interfaces/records-subscribe.d.ts.map +1 -1
- package/dist/types/src/interfaces/records-write-query.d.ts +33 -0
- package/dist/types/src/interfaces/records-write-query.d.ts.map +1 -0
- package/dist/types/src/interfaces/records-write-signing.d.ts +34 -0
- package/dist/types/src/interfaces/records-write-signing.d.ts.map +1 -0
- package/dist/types/src/interfaces/records-write.d.ts +13 -53
- package/dist/types/src/interfaces/records-write.d.ts.map +1 -1
- package/dist/types/src/protocols/permission-grant.d.ts +1 -1
- package/dist/types/src/protocols/permission-grant.d.ts.map +1 -1
- package/dist/types/src/protocols/permission-request.d.ts +1 -1
- package/dist/types/src/protocols/permission-request.d.ts.map +1 -1
- package/dist/types/src/protocols/permissions.d.ts +40 -3
- package/dist/types/src/protocols/permissions.d.ts.map +1 -1
- package/dist/types/src/state-index/state-index-level.d.ts.map +1 -1
- package/dist/types/src/store/data-store-level.d.ts +20 -4
- package/dist/types/src/store/data-store-level.d.ts.map +1 -1
- package/dist/types/src/store/index-level-compound.d.ts +70 -0
- package/dist/types/src/store/index-level-compound.d.ts.map +1 -0
- package/dist/types/src/store/index-level.d.ts +4 -58
- package/dist/types/src/store/index-level.d.ts.map +1 -1
- package/dist/types/src/store/storage-controller.d.ts +4 -4
- package/dist/types/src/store/storage-controller.d.ts.map +1 -1
- package/dist/types/src/types/message-types.d.ts +3 -3
- package/dist/types/src/types/message-types.d.ts.map +1 -1
- package/dist/types/src/types/messages-types.d.ts +12 -3
- package/dist/types/src/types/messages-types.d.ts.map +1 -1
- package/dist/types/src/types/method-handler.d.ts +24 -3
- package/dist/types/src/types/method-handler.d.ts.map +1 -1
- package/dist/types/src/types/permission-types.d.ts +7 -0
- package/dist/types/src/types/permission-types.d.ts.map +1 -1
- package/dist/types/src/types/protocols-types.d.ts +41 -1
- package/dist/types/src/types/protocols-types.d.ts.map +1 -1
- package/dist/types/src/types/records-types.d.ts +16 -6
- package/dist/types/src/types/records-types.d.ts.map +1 -1
- package/dist/types/src/types/subscriptions.d.ts +151 -13
- package/dist/types/src/types/subscriptions.d.ts.map +1 -1
- package/dist/types/src/utils/hd-key.d.ts +1 -9
- package/dist/types/src/utils/hd-key.d.ts.map +1 -1
- package/dist/types/src/utils/messages.d.ts +7 -5
- package/dist/types/src/utils/messages.d.ts.map +1 -1
- package/dist/types/src/utils/protocols.d.ts +5 -0
- package/dist/types/src/utils/protocols.d.ts.map +1 -1
- package/dist/types/src/utils/records.d.ts +1 -11
- package/dist/types/src/utils/records.d.ts.map +1 -1
- package/dist/types/tests/dwn.spec.d.ts.map +1 -1
- package/dist/types/tests/event-emitter-event-log.spec.d.ts +2 -0
- package/dist/types/tests/event-emitter-event-log.spec.d.ts.map +1 -0
- package/dist/types/tests/features/author-delegated-grant.spec.d.ts.map +1 -1
- package/dist/types/tests/features/owner-delegated-grant.spec.d.ts.map +1 -1
- package/dist/types/tests/features/owner-signature.spec.d.ts.map +1 -1
- package/dist/types/tests/features/permissions.spec.d.ts.map +1 -1
- package/dist/types/tests/features/protocol-composition.spec.d.ts.map +1 -1
- package/dist/types/tests/features/records-immutable.spec.d.ts +2 -0
- package/dist/types/tests/features/records-immutable.spec.d.ts.map +1 -0
- package/dist/types/tests/features/records-record-limit.spec.d.ts +2 -0
- package/dist/types/tests/features/records-record-limit.spec.d.ts.map +1 -0
- package/dist/types/tests/features/records-tags.spec.d.ts.map +1 -1
- package/dist/types/tests/features/resumable-tasks.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/messages-read.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/messages-subscribe.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/messages-sync.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-count.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-delete.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-query.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-read.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-subscribe.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-write.spec.d.ts.map +1 -1
- package/dist/types/tests/scenarios/deleted-record.spec.d.ts.map +1 -1
- package/dist/types/tests/scenarios/subscriptions.spec.d.ts.map +1 -1
- package/dist/types/tests/test-event-stream.d.ts +11 -12
- package/dist/types/tests/test-event-stream.d.ts.map +1 -1
- package/dist/types/tests/test-suite.d.ts +2 -2
- package/dist/types/tests/test-suite.d.ts.map +1 -1
- package/dist/types/tests/utils/test-data-generator.d.ts +18 -0
- package/dist/types/tests/utils/test-data-generator.d.ts.map +1 -1
- package/package.json +5 -4
- package/src/core/constants.ts +11 -0
- package/src/core/core-protocol.ts +129 -0
- package/src/core/dwn-error.ts +15 -12
- package/src/core/grant-authorization.ts +20 -3
- package/src/core/protocol-authorization-action.ts +377 -0
- package/src/core/protocol-authorization-validation.ts +487 -0
- package/src/core/protocol-authorization.ts +111 -856
- package/src/core/record-chain.ts +99 -0
- package/src/core/records-grant-authorization.ts +6 -8
- package/src/dwn.ts +58 -73
- package/src/event-stream/event-emitter-event-log.ts +283 -0
- package/src/handlers/messages-read.ts +8 -9
- package/src/handlers/messages-subscribe.ts +24 -28
- package/src/handlers/messages-sync.ts +10 -16
- package/src/handlers/protocols-configure.ts +47 -32
- package/src/handlers/protocols-query.ts +6 -9
- package/src/handlers/records-count.ts +11 -10
- package/src/handlers/records-delete.ts +12 -21
- package/src/handlers/records-query.ts +12 -12
- package/src/handlers/records-read.ts +34 -22
- package/src/handlers/records-subscribe.ts +47 -26
- package/src/handlers/records-write.ts +47 -104
- package/src/index.ts +9 -5
- package/src/interfaces/messages-subscribe.ts +7 -1
- package/src/interfaces/protocols-configure.ts +73 -8
- package/src/interfaces/records-count.ts +1 -1
- package/src/interfaces/records-delete.ts +1 -1
- package/src/interfaces/records-query.ts +1 -1
- package/src/interfaces/records-read.ts +1 -1
- package/src/interfaces/records-subscribe.ts +8 -1
- package/src/interfaces/records-write-query.ts +139 -0
- package/src/interfaces/records-write-signing.ts +123 -0
- package/src/interfaces/records-write.ts +66 -261
- package/src/protocols/permission-grant.ts +1 -1
- package/src/protocols/permission-request.ts +1 -1
- package/src/protocols/permissions.ts +148 -6
- package/src/state-index/state-index-level.ts +5 -7
- package/src/store/data-store-level.ts +124 -34
- package/src/store/index-level-compound.ts +324 -0
- package/src/store/index-level.ts +68 -341
- package/src/store/storage-controller.ts +11 -11
- package/src/types/message-types.ts +3 -3
- package/src/types/messages-types.ts +12 -3
- package/src/types/method-handler.ts +26 -4
- package/src/types/mitt.d.ts +28 -0
- package/src/types/permission-types.ts +7 -0
- package/src/types/protocols-types.ts +46 -0
- package/src/types/records-types.ts +16 -6
- package/src/types/subscriptions.ts +178 -14
- package/src/utils/hd-key.ts +0 -9
- package/src/utils/messages.ts +17 -37
- package/src/utils/protocols.ts +8 -0
- package/src/utils/records.ts +8 -59
- package/dist/esm/src/event-stream/event-emitter-stream.js +0 -60
- package/dist/esm/src/event-stream/event-emitter-stream.js.map +0 -1
- package/dist/esm/tests/event-stream/event-emitter-stream.spec.js +0 -77
- package/dist/esm/tests/event-stream/event-emitter-stream.spec.js.map +0 -1
- package/dist/esm/tests/event-stream/event-stream.spec.js +0 -123
- package/dist/esm/tests/event-stream/event-stream.spec.js.map +0 -1
- package/dist/types/src/event-stream/event-emitter-stream.d.ts +0 -23
- package/dist/types/src/event-stream/event-emitter-stream.d.ts.map +0 -1
- package/dist/types/tests/event-stream/event-emitter-stream.spec.d.ts +0 -2
- package/dist/types/tests/event-stream/event-emitter-stream.spec.d.ts.map +0 -1
- package/dist/types/tests/event-stream/event-stream.spec.d.ts +0 -2
- package/dist/types/tests/event-stream/event-stream.spec.d.ts.map +0 -1
- package/src/event-stream/event-emitter-stream.ts +0 -69
|
@@ -1,72 +1,41 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
11
|
-
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
12
|
-
var m = o[Symbol.asyncIterator], i;
|
|
13
|
-
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
14
|
-
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
15
|
-
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
16
|
-
};
|
|
17
|
-
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
|
|
18
|
-
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
|
|
19
|
-
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
20
|
-
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
|
21
|
-
return i = {}, verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
|
|
22
|
-
function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
|
|
23
|
-
function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }
|
|
24
|
-
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
|
|
25
|
-
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
|
|
26
|
-
function fulfill(value) { resume("next", value); }
|
|
27
|
-
function reject(value) { resume("throw", value); }
|
|
28
|
-
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
|
|
29
|
-
};
|
|
30
1
|
import { isEmptyObject } from '../utils/object.js';
|
|
31
2
|
import { lexicographicalCompare } from '../utils/string.js';
|
|
32
3
|
import { SortDirection } from '../types/query-types.js';
|
|
4
|
+
import { countWithCompoundIndex, createCompoundIndexDeleteOperation, createCompoundIndexPutOperation, queryWithCompoundIndex, selectCompoundIndex, } from './index-level-compound.js';
|
|
33
5
|
import { createLevelDatabase, LevelWrapper } from './level-wrapper.js';
|
|
34
6
|
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
|
|
35
7
|
import { FilterSelector, FilterUtility } from '../utils/filter.js';
|
|
36
8
|
const INDEX_SUBLEVEL_NAME = 'index';
|
|
37
|
-
/** Separator between compound key segments (higher than \x00 so prefix scans work correctly). */
|
|
38
|
-
const COMPOUND_SEGMENT_SEPARATOR = '\x01';
|
|
39
9
|
/**
|
|
40
10
|
* A LevelDB implementation for indexing the messages and events stored in the DWN.
|
|
41
11
|
*/
|
|
42
12
|
export class IndexLevel {
|
|
13
|
+
db;
|
|
14
|
+
config;
|
|
15
|
+
_compoundIndexes;
|
|
43
16
|
constructor(config) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
17
|
+
this.config = {
|
|
18
|
+
createLevelDatabase,
|
|
19
|
+
...config,
|
|
20
|
+
};
|
|
21
|
+
this._compoundIndexes = config.compoundIndexes ?? [];
|
|
47
22
|
this.db = new LevelWrapper({
|
|
48
23
|
location: this.config.location,
|
|
49
24
|
createLevelDatabase: this.config.createLevelDatabase,
|
|
50
25
|
keyEncoding: 'utf8'
|
|
51
26
|
});
|
|
52
27
|
}
|
|
53
|
-
open() {
|
|
54
|
-
|
|
55
|
-
yield this.db.open();
|
|
56
|
-
});
|
|
28
|
+
async open() {
|
|
29
|
+
await this.db.open();
|
|
57
30
|
}
|
|
58
|
-
close() {
|
|
59
|
-
|
|
60
|
-
yield this.db.close();
|
|
61
|
-
});
|
|
31
|
+
async close() {
|
|
32
|
+
await this.db.close();
|
|
62
33
|
}
|
|
63
34
|
/**
|
|
64
35
|
* deletes everything in the underlying index db.
|
|
65
36
|
*/
|
|
66
|
-
clear() {
|
|
67
|
-
|
|
68
|
-
yield this.db.clear();
|
|
69
|
-
});
|
|
37
|
+
async clear() {
|
|
38
|
+
await this.db.clear();
|
|
70
39
|
}
|
|
71
40
|
/**
|
|
72
41
|
* Put an item into the index using information that will allow it to be queried for.
|
|
@@ -76,132 +45,120 @@ export class IndexLevel {
|
|
|
76
45
|
* @param indexes - (key-value pairs) to be included as part of indexing this item. Must include at least one indexing property.
|
|
77
46
|
* @param options IndexLevelOptions that include an AbortSignal.
|
|
78
47
|
*/
|
|
79
|
-
put(tenant, messageCid, indexes, options) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const partitionOperationPromise = this.createPutIndexedItemOperation(tenant, item, indexName, indexValueItem);
|
|
94
|
-
opCreationPromises.push(partitionOperationPromise);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
else {
|
|
98
|
-
const partitionOperationPromise = this.createPutIndexedItemOperation(tenant, item, indexName, indexValue);
|
|
48
|
+
async put(tenant, messageCid, indexes, options) {
|
|
49
|
+
// ensure we have something valid to index
|
|
50
|
+
if (isEmptyObject(indexes)) {
|
|
51
|
+
throw new DwnError(DwnErrorCode.IndexMissingIndexableProperty, 'Index must include at least one valid indexable property');
|
|
52
|
+
}
|
|
53
|
+
const item = { messageCid, indexes };
|
|
54
|
+
const opCreationPromises = [];
|
|
55
|
+
// create an index entry for each property index
|
|
56
|
+
// these indexes are all sortable lexicographically.
|
|
57
|
+
for (const indexName in indexes) {
|
|
58
|
+
const indexValue = indexes[indexName];
|
|
59
|
+
if (Array.isArray(indexValue)) {
|
|
60
|
+
for (const indexValueItem of indexValue) {
|
|
61
|
+
const partitionOperationPromise = this.createPutIndexedItemOperation(tenant, item, indexName, indexValueItem);
|
|
99
62
|
opCreationPromises.push(partitionOperationPromise);
|
|
100
63
|
}
|
|
101
64
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (compoundOp !== undefined) {
|
|
106
|
-
opCreationPromises.push(compoundOp);
|
|
107
|
-
}
|
|
65
|
+
else {
|
|
66
|
+
const partitionOperationPromise = this.createPutIndexedItemOperation(tenant, item, indexName, indexValue);
|
|
67
|
+
opCreationPromises.push(partitionOperationPromise);
|
|
108
68
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
69
|
+
}
|
|
70
|
+
// create compound index entries for any registered compound indexes whose properties are all present in the indexes.
|
|
71
|
+
for (const compoundIndex of this._compoundIndexes) {
|
|
72
|
+
const compoundOp = createCompoundIndexPutOperation(this.db, tenant, item, compoundIndex, IndexLevel.encodeValue, IndexLevel.delimiter);
|
|
73
|
+
if (compoundOp !== undefined) {
|
|
74
|
+
opCreationPromises.push(compoundOp);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// create a reverse lookup for the sortedIndex values. This is used during deletion and cursor starting point lookup.
|
|
78
|
+
const partitionOperationPromise = this.createOperationForIndexesLookupPartition(tenant, { type: 'put', key: messageCid, value: JSON.stringify(indexes) });
|
|
79
|
+
opCreationPromises.push(partitionOperationPromise);
|
|
80
|
+
const indexOps = await Promise.all(opCreationPromises);
|
|
81
|
+
const tenantPartition = await this.db.partition(tenant);
|
|
82
|
+
await tenantPartition.batch(indexOps, options);
|
|
116
83
|
}
|
|
117
84
|
/**
|
|
118
85
|
* Deletes all of the index data associated with the item.
|
|
119
86
|
*/
|
|
120
|
-
delete(tenant, messageCid, options) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
const partitionOperationPromise = this.createDeleteIndexedItemOperation(tenant, messageCid, indexName, indexValueItem);
|
|
137
|
-
opCreationPromises.push(partitionOperationPromise);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
else {
|
|
141
|
-
const partitionOperationPromise = this.createDeleteIndexedItemOperation(tenant, messageCid, indexName, indexValue);
|
|
87
|
+
async delete(tenant, messageCid, options) {
|
|
88
|
+
const opCreationPromises = [];
|
|
89
|
+
const indexes = await this.getIndexes(tenant, messageCid);
|
|
90
|
+
if (indexes === undefined) {
|
|
91
|
+
// invalid messageCid
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
// delete the reverse lookup
|
|
95
|
+
const partitionOperationPromise = this.createOperationForIndexesLookupPartition(tenant, { type: 'del', key: messageCid });
|
|
96
|
+
opCreationPromises.push(partitionOperationPromise);
|
|
97
|
+
// delete the keys for each index
|
|
98
|
+
for (const indexName in indexes) {
|
|
99
|
+
const indexValue = indexes[indexName];
|
|
100
|
+
if (Array.isArray(indexValue)) {
|
|
101
|
+
for (const indexValueItem of indexValue) {
|
|
102
|
+
const partitionOperationPromise = this.createDeleteIndexedItemOperation(tenant, messageCid, indexName, indexValueItem);
|
|
142
103
|
opCreationPromises.push(partitionOperationPromise);
|
|
143
104
|
}
|
|
144
105
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if (compoundOp !== undefined) {
|
|
149
|
-
opCreationPromises.push(compoundOp);
|
|
150
|
-
}
|
|
106
|
+
else {
|
|
107
|
+
const partitionOperationPromise = this.createDeleteIndexedItemOperation(tenant, messageCid, indexName, indexValue);
|
|
108
|
+
opCreationPromises.push(partitionOperationPromise);
|
|
151
109
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
110
|
+
}
|
|
111
|
+
// delete compound index entries
|
|
112
|
+
for (const compoundIndex of this._compoundIndexes) {
|
|
113
|
+
const compoundOp = createCompoundIndexDeleteOperation(this.db, tenant, messageCid, indexes, compoundIndex, IndexLevel.encodeValue, IndexLevel.delimiter);
|
|
114
|
+
if (compoundOp !== undefined) {
|
|
115
|
+
opCreationPromises.push(compoundOp);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const indexOps = await Promise.all(opCreationPromises);
|
|
119
|
+
const tenantPartition = await this.db.partition(tenant);
|
|
120
|
+
await tenantPartition.batch(indexOps, options);
|
|
156
121
|
}
|
|
157
122
|
/**
|
|
158
123
|
* Creates an IndexLevel `put` operation for indexing an item, creating a partition by `tenant` and by `indexName`
|
|
159
124
|
*/
|
|
160
|
-
createPutIndexedItemOperation(tenant, item, indexName, indexValue) {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
return this.createOperationForIndexPartition(tenant, indexName, { type: 'put', key, value: JSON.stringify(item) });
|
|
168
|
-
});
|
|
125
|
+
async createPutIndexedItemOperation(tenant, item, indexName, indexValue) {
|
|
126
|
+
const { messageCid } = item;
|
|
127
|
+
// The key is the indexValue followed by the messageCid as a tie-breaker.
|
|
128
|
+
// for example if the property is messageTimestamp the key would look like:
|
|
129
|
+
// '"2023-05-25T18:23:29.425008Z"\u0000bafyreigs3em7lrclhntzhgvkrf75j2muk6e7ypq3lrw3ffgcpyazyw6pry'
|
|
130
|
+
const key = IndexLevel.keySegmentJoin(IndexLevel.encodeValue(indexValue), messageCid);
|
|
131
|
+
return this.createOperationForIndexPartition(tenant, indexName, { type: 'put', key, value: JSON.stringify(item) });
|
|
169
132
|
}
|
|
170
133
|
/**
|
|
171
134
|
* Creates an IndexLevel `del` operation for deleting an item, creating a partition by `tenant` and by `indexName`
|
|
172
135
|
*/
|
|
173
|
-
createDeleteIndexedItemOperation(tenant, messageCid, indexName, indexValue) {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
return this.createOperationForIndexPartition(tenant, indexName, { type: 'del', key });
|
|
180
|
-
});
|
|
136
|
+
async createDeleteIndexedItemOperation(tenant, messageCid, indexName, indexValue) {
|
|
137
|
+
// The key is the indexValue followed by the messageCid as a tie-breaker.
|
|
138
|
+
// for example if the property is messageTimestamp the key would look like:
|
|
139
|
+
// '"2023-05-25T18:23:29.425008Z"\u0000bafyreigs3em7lrclhntzhgvkrf75j2muk6e7ypq3lrw3ffgcpyazyw6pry'
|
|
140
|
+
const key = IndexLevel.keySegmentJoin(IndexLevel.encodeValue(indexValue), messageCid);
|
|
141
|
+
return this.createOperationForIndexPartition(tenant, indexName, { type: 'del', key });
|
|
181
142
|
}
|
|
182
143
|
/**
|
|
183
144
|
* Wraps the given operation as an operation for the specified index partition.
|
|
184
145
|
*/
|
|
185
|
-
createOperationForIndexPartition(tenant, indexName, operation) {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
return partitionOperation;
|
|
194
|
-
});
|
|
146
|
+
async createOperationForIndexPartition(tenant, indexName, operation) {
|
|
147
|
+
// we write the index entry into a sublevel-partition of tenantPartition.
|
|
148
|
+
// putting each index entry within a sublevel allows the levelDB system to calculate a gt minKey and lt maxKey for each of the properties
|
|
149
|
+
// this prevents them from clashing, especially when iterating in reverse without iterating through other properties.
|
|
150
|
+
const tenantPartition = await this.db.partition(tenant);
|
|
151
|
+
const indexPartitionName = IndexLevel.getIndexPartitionName(indexName);
|
|
152
|
+
const partitionOperation = tenantPartition.createPartitionOperation(indexPartitionName, operation);
|
|
153
|
+
return partitionOperation;
|
|
195
154
|
}
|
|
196
155
|
/**
|
|
197
156
|
* Wraps the given operation as an operation for the messageCid to indexes lookup partition.
|
|
198
157
|
*/
|
|
199
|
-
createOperationForIndexesLookupPartition(tenant, operation) {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
return partitionOperation;
|
|
204
|
-
});
|
|
158
|
+
async createOperationForIndexesLookupPartition(tenant, operation) {
|
|
159
|
+
const tenantPartition = await this.db.partition(tenant);
|
|
160
|
+
const partitionOperation = tenantPartition.createPartitionOperation(INDEX_SUBLEVEL_NAME, operation);
|
|
161
|
+
return partitionOperation;
|
|
205
162
|
}
|
|
206
163
|
static getIndexPartitionName(indexName) {
|
|
207
164
|
// we create index partition names in __${indexName}__ wrapping so they do not clash with other sublevels that are created for other purposes.
|
|
@@ -210,19 +167,15 @@ export class IndexLevel {
|
|
|
210
167
|
/**
|
|
211
168
|
* Gets the index partition of the given indexName.
|
|
212
169
|
*/
|
|
213
|
-
getIndexPartition(tenant, indexName) {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
return (yield this.db.partition(tenant)).partition(indexPartitionName);
|
|
217
|
-
});
|
|
170
|
+
async getIndexPartition(tenant, indexName) {
|
|
171
|
+
const indexPartitionName = IndexLevel.getIndexPartitionName(indexName);
|
|
172
|
+
return (await this.db.partition(tenant)).partition(indexPartitionName);
|
|
218
173
|
}
|
|
219
174
|
/**
|
|
220
175
|
* Gets the messageCid to indexes lookup partition.
|
|
221
176
|
*/
|
|
222
|
-
getIndexesLookupPartition(tenant) {
|
|
223
|
-
return
|
|
224
|
-
return (yield this.db.partition(tenant)).partition(INDEX_SUBLEVEL_NAME);
|
|
225
|
-
});
|
|
177
|
+
async getIndexesLookupPartition(tenant) {
|
|
178
|
+
return (await this.db.partition(tenant)).partition(INDEX_SUBLEVEL_NAME);
|
|
226
179
|
}
|
|
227
180
|
/**
|
|
228
181
|
* Queries the index for items that match the filters. If no filters are provided, all items are returned.
|
|
@@ -238,22 +191,20 @@ export class IndexLevel {
|
|
|
238
191
|
* @param options IndexLevelOptions that include an AbortSignal.
|
|
239
192
|
* @returns {IndexedItem[]} an array of `IndexedItem` that match the given filters.
|
|
240
193
|
*/
|
|
241
|
-
query(tenant, filters, queryOptions, options) {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
return this.queryWithCompoundIndex(tenant, filters[0], queryOptions, compoundResult, options);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
// Strategy 2: in-memory paging for concise filters
|
|
251
|
-
if (IndexLevel.shouldQueryWithInMemoryPaging(filters, queryOptions)) {
|
|
252
|
-
return this.queryWithInMemoryPaging(tenant, filters, queryOptions, options);
|
|
194
|
+
async query(tenant, filters, queryOptions, options) {
|
|
195
|
+
// Strategy 1: try compound index for single-filter queries
|
|
196
|
+
if (filters.length === 1 && !isEmptyObject(filters[0])) {
|
|
197
|
+
const compoundResult = selectCompoundIndex(filters[0], queryOptions, this._compoundIndexes);
|
|
198
|
+
if (compoundResult !== undefined) {
|
|
199
|
+
return queryWithCompoundIndex(this.db, tenant, filters[0], queryOptions, compoundResult, IndexLevel.encodeValue, IndexLevel.delimiter, this.queryWithIteratorPaging.bind(this), options);
|
|
253
200
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
201
|
+
}
|
|
202
|
+
// Strategy 2: in-memory paging for concise filters
|
|
203
|
+
if (IndexLevel.shouldQueryWithInMemoryPaging(filters, queryOptions)) {
|
|
204
|
+
return this.queryWithInMemoryPaging(tenant, filters, queryOptions, options);
|
|
205
|
+
}
|
|
206
|
+
// Strategy 3: iterator paging (default)
|
|
207
|
+
return this.queryWithIteratorPaging(tenant, filters, queryOptions, options);
|
|
257
208
|
}
|
|
258
209
|
/**
|
|
259
210
|
* Counts the number of items that match the given filters without loading full records.
|
|
@@ -261,94 +212,62 @@ export class IndexLevel {
|
|
|
261
212
|
* When a compound index covers the query, counting is a simple key iteration without value deserialization.
|
|
262
213
|
* Otherwise, falls back to counting via the existing query strategies.
|
|
263
214
|
*/
|
|
264
|
-
count(tenant, filters, queryOptions, options) {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
return this.countWithCompoundIndex(tenant, filters[0], compoundResult, options);
|
|
271
|
-
}
|
|
215
|
+
async count(tenant, filters, queryOptions, options) {
|
|
216
|
+
// try compound index for single-filter queries
|
|
217
|
+
if (filters.length === 1 && !isEmptyObject(filters[0])) {
|
|
218
|
+
const compoundResult = selectCompoundIndex(filters[0], { ...queryOptions }, this._compoundIndexes);
|
|
219
|
+
if (compoundResult !== undefined) {
|
|
220
|
+
return countWithCompoundIndex(this.db, tenant, filters[0], compoundResult, IndexLevel.encodeValue, this.query.bind(this), options);
|
|
272
221
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
222
|
+
}
|
|
223
|
+
// fallback: run a full query without limit and count the results
|
|
224
|
+
const results = await this.query(tenant, filters, { ...queryOptions }, options);
|
|
225
|
+
return results.length;
|
|
277
226
|
}
|
|
278
227
|
/**
|
|
279
228
|
* Queries the sort property index for items that match the filters. If no filters are provided, all items are returned.
|
|
280
229
|
* This query is a linear iterator over the sorted index, checking each item for a match.
|
|
281
230
|
* If a cursor is provided it starts the iteration from the cursor point.
|
|
282
231
|
*/
|
|
283
|
-
queryWithIteratorPaging(tenant, filters, queryOptions, options) {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
for (var _d = true, _e = __asyncValues(this.getIndexIterator(tenant, startKey, queryOptions, options)), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
|
|
292
|
-
_c = _f.value;
|
|
293
|
-
_d = false;
|
|
294
|
-
const item = _c;
|
|
295
|
-
if (limit !== undefined && limit === matches.length) {
|
|
296
|
-
break;
|
|
297
|
-
}
|
|
298
|
-
const { indexes } = item;
|
|
299
|
-
if (FilterUtility.matchAnyFilter(indexes, filters)) {
|
|
300
|
-
matches.push(item);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
232
|
+
async queryWithIteratorPaging(tenant, filters, queryOptions, options) {
|
|
233
|
+
const { cursor: queryCursor, limit } = queryOptions;
|
|
234
|
+
// if there is a cursor we fetch the starting key given the sort property, otherwise we start from the beginning of the index.
|
|
235
|
+
const startKey = queryCursor ? this.createStartingKeyFromCursor(queryCursor) : '';
|
|
236
|
+
const matches = [];
|
|
237
|
+
for await (const item of this.getIndexIterator(tenant, startKey, queryOptions, options)) {
|
|
238
|
+
if (limit !== undefined && limit === matches.length) {
|
|
239
|
+
break;
|
|
303
240
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
308
|
-
}
|
|
309
|
-
finally { if (e_1) throw e_1.error; }
|
|
241
|
+
const { indexes } = item;
|
|
242
|
+
if (FilterUtility.matchAnyFilter(indexes, filters)) {
|
|
243
|
+
matches.push(item);
|
|
310
244
|
}
|
|
311
|
-
|
|
312
|
-
|
|
245
|
+
}
|
|
246
|
+
return matches;
|
|
313
247
|
}
|
|
314
248
|
/**
|
|
315
249
|
* Creates an AsyncGenerator that returns each sorted index item given a specific sortProperty.
|
|
316
250
|
* If a cursor is passed, the starting value (gt or lt) is derived from that.
|
|
317
251
|
*/
|
|
318
|
-
getIndexIterator(tenant, startKey, queryOptions, options) {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
if
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
iteratorOptions.lt = startKey;
|
|
331
|
-
delete iteratorOptions.gt;
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
const sortPartition = yield __await(this.getIndexPartition(tenant, sortProperty));
|
|
335
|
-
try {
|
|
336
|
-
for (var _d = true, _e = __asyncValues(sortPartition.iterator(iteratorOptions, options)), _f; _f = yield __await(_e.next()), _a = _f.done, !_a; _d = true) {
|
|
337
|
-
_c = _f.value;
|
|
338
|
-
_d = false;
|
|
339
|
-
const [_, val] = _c;
|
|
340
|
-
const { indexes, messageCid } = JSON.parse(val);
|
|
341
|
-
yield yield __await({ indexes, messageCid });
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
345
|
-
finally {
|
|
346
|
-
try {
|
|
347
|
-
if (!_d && !_a && (_b = _e.return)) yield __await(_b.call(_e));
|
|
348
|
-
}
|
|
349
|
-
finally { if (e_2) throw e_2.error; }
|
|
252
|
+
async *getIndexIterator(tenant, startKey, queryOptions, options) {
|
|
253
|
+
const { sortProperty, sortDirection = SortDirection.Ascending, cursor } = queryOptions;
|
|
254
|
+
const iteratorOptions = {
|
|
255
|
+
gt: startKey
|
|
256
|
+
};
|
|
257
|
+
// if we are sorting in descending order we can iterate in reverse.
|
|
258
|
+
if (sortDirection === SortDirection.Descending) {
|
|
259
|
+
iteratorOptions.reverse = true;
|
|
260
|
+
// if a cursor is provided and we are sorting in descending order, the startKey should be the upper bound.
|
|
261
|
+
if (cursor !== undefined) {
|
|
262
|
+
iteratorOptions.lt = startKey;
|
|
263
|
+
delete iteratorOptions.gt;
|
|
350
264
|
}
|
|
351
|
-
}
|
|
265
|
+
}
|
|
266
|
+
const sortPartition = await this.getIndexPartition(tenant, sortProperty);
|
|
267
|
+
for await (const [_, val] of sortPartition.iterator(iteratorOptions, options)) {
|
|
268
|
+
const { indexes, messageCid } = JSON.parse(val);
|
|
269
|
+
yield { indexes, messageCid };
|
|
270
|
+
}
|
|
352
271
|
}
|
|
353
272
|
/**
|
|
354
273
|
* Creates the starting point for a LevelDB query given an messageCid as a cursor and the indexed property.
|
|
@@ -394,151 +313,127 @@ export class IndexLevel {
|
|
|
394
313
|
*
|
|
395
314
|
* @throws {DwnErrorCode.IndexLevelInMemoryInvalidSortProperty} if an invalid sort property is provided.
|
|
396
315
|
*/
|
|
397
|
-
queryWithInMemoryPaging(tenant, filters, queryOptions, options) {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
316
|
+
async queryWithInMemoryPaging(tenant, filters, queryOptions, options) {
|
|
317
|
+
const { sortProperty, sortDirection = SortDirection.Ascending, cursor: queryCursor, limit } = queryOptions;
|
|
318
|
+
// we get the cursor start key here so that we match the failing behavior of `queryWithIteratorPaging`
|
|
319
|
+
const cursorStartingKey = queryCursor ? this.createStartingKeyFromCursor(queryCursor) : undefined;
|
|
320
|
+
// we create a matches map so that we can short-circuit matched items within the async single query below.
|
|
321
|
+
const matches = new Map();
|
|
322
|
+
// If the filter is empty, we just give it an empty filter so that we can iterate over all the items later in executeSingleFilterQuery().
|
|
323
|
+
// We could do the iteration here, but it would be duplicating the same logic, so decided to just setup the data structure here.
|
|
324
|
+
if (filters.length === 0) {
|
|
325
|
+
filters = [{}];
|
|
326
|
+
}
|
|
327
|
+
try {
|
|
328
|
+
// Execute filters sequentially rather than with Promise.all.
|
|
329
|
+
// Firefox's IndexedDB implementation has two related async issues that cause flaky failures:
|
|
330
|
+
// 1. Concurrent cursors/transactions can silently miss recently-committed data
|
|
331
|
+
// 2. A read transaction opened immediately after a write transaction's oncomplete event
|
|
332
|
+
// can fail to see the written data (write-read race)
|
|
333
|
+
// Serializing eliminates both races. Performance impact is negligible: only 3 call sites
|
|
334
|
+
// (non-owner RecordsQuery/Subscribe/Count) ever pass multiple filters, and each filter
|
|
335
|
+
// reduces to a single bounded LevelDB range scan completing in single-digit ms.
|
|
336
|
+
// See: https://github.com/enboxorg/enbox/issues/264
|
|
337
|
+
for (const filter of filters) {
|
|
338
|
+
await this.executeSingleFilterQuery(tenant, filter, sortProperty, matches, options);
|
|
419
339
|
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
if (
|
|
423
|
-
//
|
|
340
|
+
}
|
|
341
|
+
catch (error) {
|
|
342
|
+
if (error.code === DwnErrorCode.IndexInvalidSortPropertyInMemory) {
|
|
343
|
+
// return empty results if the sort property is invalid.
|
|
424
344
|
return [];
|
|
425
345
|
}
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
346
|
+
}
|
|
347
|
+
const sortedValues = [...matches.values()].sort((a, b) => this.sortItems(a, b, sortProperty, sortDirection));
|
|
348
|
+
const start = cursorStartingKey !== undefined ? this.findCursorStartingIndex(sortedValues, sortDirection, sortProperty, cursorStartingKey) : 0;
|
|
349
|
+
if (start < 0) {
|
|
350
|
+
// if the provided cursor does not come before any of the results, we return no results
|
|
351
|
+
return [];
|
|
352
|
+
}
|
|
353
|
+
const end = limit !== undefined ? start + limit : undefined;
|
|
354
|
+
return sortedValues.slice(start, end);
|
|
429
355
|
}
|
|
430
356
|
/**
|
|
431
357
|
* Execute a filtered query against a single filter and return all results.
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
else if (FilterUtility.isOneOfFilter(propertyFilter)) {
|
|
453
|
-
// `propertyFilter` is a OneOfFilter
|
|
454
|
-
// Support OR matches by querying for each values separately, then adding them to the promises array.
|
|
455
|
-
for (const propertyValue of new Set(propertyFilter)) {
|
|
456
|
-
const exactMatchesPromise = this.filterExactMatches(tenant, propertyName, propertyValue, levelOptions);
|
|
457
|
-
filterPromises.push(exactMatchesPromise);
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
else if (FilterUtility.isRangeFilter(propertyFilter)) {
|
|
461
|
-
// `propertyFilter` is a `RangeFilter`
|
|
462
|
-
const rangeMatchesPromise = this.filterRangeMatches(tenant, propertyName, propertyFilter, levelOptions);
|
|
463
|
-
filterPromises.push(rangeMatchesPromise);
|
|
464
|
-
}
|
|
358
|
+
*
|
|
359
|
+
* Sub-queries (exact match, range, OneOf) are executed sequentially to avoid opening
|
|
360
|
+
* multiple concurrent IndexedDB cursors. Firefox's IDB implementation intermittently
|
|
361
|
+
* drops results when cursors overlap — see https://github.com/enboxorg/enbox/issues/264
|
|
362
|
+
*/
|
|
363
|
+
async executeSingleFilterQuery(tenant, filter, sortProperty, matches, levelOptions) {
|
|
364
|
+
// Collects results from each sub-query sequentially to avoid concurrent IndexedDB cursor races in Firefox.
|
|
365
|
+
const processResults = (indexItems) => {
|
|
366
|
+
for (const indexedItem of indexItems) {
|
|
367
|
+
// short circuit: if a data is already included to the final matched key set (by a different `Filter`),
|
|
368
|
+
// no need to evaluate if the data satisfies this current filter being evaluated
|
|
369
|
+
// otherwise check that the item is a match.
|
|
370
|
+
if (matches.has(indexedItem.messageCid) || !FilterUtility.matchFilter(indexedItem.indexes, filter)) {
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
// ensure that each matched item has the sortProperty, otherwise fail the entire query.
|
|
374
|
+
if (indexedItem.indexes[sortProperty] === undefined) {
|
|
375
|
+
throw new DwnError(DwnErrorCode.IndexInvalidSortPropertyInMemory, `invalid sort property ${sortProperty}`);
|
|
376
|
+
}
|
|
377
|
+
matches.set(indexedItem.messageCid, indexedItem);
|
|
465
378
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
379
|
+
};
|
|
380
|
+
// If the filter is empty, then we just iterate over one of the indexes that contains all the records and return all items.
|
|
381
|
+
if (isEmptyObject(filter)) {
|
|
382
|
+
const allItems = await this.getAllItems(tenant, sortProperty);
|
|
383
|
+
processResults(allItems);
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
// else the filter is not empty
|
|
387
|
+
const searchFilter = FilterSelector.reduceFilter(filter);
|
|
388
|
+
for (const propertyName in searchFilter) {
|
|
389
|
+
const propertyFilter = searchFilter[propertyName];
|
|
390
|
+
// We will find the union of these many individual queries later.
|
|
391
|
+
if (FilterUtility.isEqualFilter(propertyFilter)) {
|
|
392
|
+
// propertyFilter is an EqualFilter, meaning it is a non-object primitive type
|
|
393
|
+
const exactMatches = await this.filterExactMatches(tenant, propertyName, propertyFilter, levelOptions);
|
|
394
|
+
processResults(exactMatches);
|
|
395
|
+
}
|
|
396
|
+
else if (FilterUtility.isOneOfFilter(propertyFilter)) {
|
|
397
|
+
// `propertyFilter` is a OneOfFilter
|
|
398
|
+
// Support OR matches by querying for each value separately and sequentially.
|
|
399
|
+
for (const propertyValue of new Set(propertyFilter)) {
|
|
400
|
+
const exactMatches = await this.filterExactMatches(tenant, propertyName, propertyValue, levelOptions);
|
|
401
|
+
processResults(exactMatches);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
else if (FilterUtility.isRangeFilter(propertyFilter)) {
|
|
405
|
+
// `propertyFilter` is a `RangeFilter`
|
|
406
|
+
const rangeMatches = await this.filterRangeMatches(tenant, propertyName, propertyFilter, levelOptions);
|
|
407
|
+
processResults(rangeMatches);
|
|
483
408
|
}
|
|
484
|
-
}
|
|
409
|
+
}
|
|
485
410
|
}
|
|
486
|
-
getAllItems(tenant, sortProperty) {
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
_c = _f.value;
|
|
494
|
-
_d = false;
|
|
495
|
-
const [_key, value] = _c;
|
|
496
|
-
items.push(JSON.parse(value));
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
500
|
-
finally {
|
|
501
|
-
try {
|
|
502
|
-
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
503
|
-
}
|
|
504
|
-
finally { if (e_3) throw e_3.error; }
|
|
505
|
-
}
|
|
506
|
-
return items;
|
|
507
|
-
});
|
|
411
|
+
async getAllItems(tenant, sortProperty) {
|
|
412
|
+
const filterPartition = await this.getIndexPartition(tenant, sortProperty);
|
|
413
|
+
const items = [];
|
|
414
|
+
for await (const [_key, value] of filterPartition.iterator()) {
|
|
415
|
+
items.push(JSON.parse(value));
|
|
416
|
+
}
|
|
417
|
+
return items;
|
|
508
418
|
}
|
|
509
419
|
/**
|
|
510
420
|
* Returns items that match the exact property and value.
|
|
511
421
|
*/
|
|
512
|
-
filterExactMatches(tenant, propertyName, propertyValue, options) {
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
if (!key.startsWith(matchPrefix)) {
|
|
528
|
-
break;
|
|
529
|
-
}
|
|
530
|
-
matches.push(JSON.parse(value));
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
catch (e_4_1) { e_4 = { error: e_4_1 }; }
|
|
534
|
-
finally {
|
|
535
|
-
try {
|
|
536
|
-
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
537
|
-
}
|
|
538
|
-
finally { if (e_4) throw e_4.error; }
|
|
539
|
-
}
|
|
540
|
-
return matches;
|
|
541
|
-
});
|
|
422
|
+
async filterExactMatches(tenant, propertyName, propertyValue, options) {
|
|
423
|
+
const matchPrefix = IndexLevel.keySegmentJoin(IndexLevel.encodeValue(propertyValue));
|
|
424
|
+
const iteratorOptions = {
|
|
425
|
+
gt: matchPrefix
|
|
426
|
+
};
|
|
427
|
+
const filterPartition = await this.getIndexPartition(tenant, propertyName);
|
|
428
|
+
const matches = [];
|
|
429
|
+
for await (const [key, value] of filterPartition.iterator(iteratorOptions, options)) {
|
|
430
|
+
// immediately stop if we arrive at an index that contains a different property value
|
|
431
|
+
if (!key.startsWith(matchPrefix)) {
|
|
432
|
+
break;
|
|
433
|
+
}
|
|
434
|
+
matches.push(JSON.parse(value));
|
|
435
|
+
}
|
|
436
|
+
return matches;
|
|
542
437
|
}
|
|
543
438
|
/**
|
|
544
439
|
* Returns items that match the range filter.
|
|
@@ -547,51 +442,36 @@ export class IndexLevel {
|
|
|
547
442
|
* of the form `<encodedValue>\x00<messageCid>` are naturally included in the range scan,
|
|
548
443
|
* eliminating the need for a separate exact-match query.
|
|
549
444
|
*/
|
|
550
|
-
filterRangeMatches(tenant, propertyName, rangeFilter, options) {
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
const
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
// will be lexicographically less than encodedValue + \xff.
|
|
561
|
-
iteratorOptions[comparatorName] = encodedValue + '\xff';
|
|
562
|
-
}
|
|
563
|
-
else {
|
|
564
|
-
iteratorOptions[comparatorName] = encodedValue;
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
// if there is no lower bound specified (`gt` or `gte`), we need to iterate from the upper bound,
|
|
568
|
-
// so that we will iterate over all the matches before hitting mismatches.
|
|
569
|
-
if (iteratorOptions.gt === undefined && iteratorOptions.gte === undefined) {
|
|
570
|
-
iteratorOptions.reverse = true;
|
|
445
|
+
async filterRangeMatches(tenant, propertyName, rangeFilter, options) {
|
|
446
|
+
const iteratorOptions = {};
|
|
447
|
+
for (const comparator in rangeFilter) {
|
|
448
|
+
const comparatorName = comparator;
|
|
449
|
+
const encodedValue = IndexLevel.encodeValue(rangeFilter[comparatorName]);
|
|
450
|
+
if (comparatorName === 'lte') {
|
|
451
|
+
// Extend the lte bound so that composite keys `<encodedValue>\x00<messageCid>` are included.
|
|
452
|
+
// Since \x00 < \xff, any key starting with encodedValue followed by the \x00 delimiter
|
|
453
|
+
// will be lexicographically less than encodedValue + \xff.
|
|
454
|
+
iteratorOptions[comparatorName] = encodedValue + '\xff';
|
|
571
455
|
}
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
try {
|
|
575
|
-
for (var _d = true, _e = __asyncValues(filterPartition.iterator(iteratorOptions, options)), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
|
|
576
|
-
_c = _f.value;
|
|
577
|
-
_d = false;
|
|
578
|
-
const [key, value] = _c;
|
|
579
|
-
// if "greater-than" is specified, skip all keys that contain the exact value given in the "greater-than" condition
|
|
580
|
-
if ('gt' in rangeFilter && this.extractIndexValueFromKey(key) === IndexLevel.encodeValue(rangeFilter.gt)) {
|
|
581
|
-
continue;
|
|
582
|
-
}
|
|
583
|
-
matches.push(JSON.parse(value));
|
|
584
|
-
}
|
|
456
|
+
else {
|
|
457
|
+
iteratorOptions[comparatorName] = encodedValue;
|
|
585
458
|
}
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
459
|
+
}
|
|
460
|
+
// if there is no lower bound specified (`gt` or `gte`), we need to iterate from the upper bound,
|
|
461
|
+
// so that we will iterate over all the matches before hitting mismatches.
|
|
462
|
+
if (iteratorOptions.gt === undefined && iteratorOptions.gte === undefined) {
|
|
463
|
+
iteratorOptions.reverse = true;
|
|
464
|
+
}
|
|
465
|
+
const matches = [];
|
|
466
|
+
const filterPartition = await this.getIndexPartition(tenant, propertyName);
|
|
467
|
+
for await (const [key, value] of filterPartition.iterator(iteratorOptions, options)) {
|
|
468
|
+
// if "greater-than" is specified, skip all keys that contain the exact value given in the "greater-than" condition
|
|
469
|
+
if ('gt' in rangeFilter && this.extractIndexValueFromKey(key) === IndexLevel.encodeValue(rangeFilter.gt)) {
|
|
470
|
+
continue;
|
|
592
471
|
}
|
|
593
|
-
|
|
594
|
-
}
|
|
472
|
+
matches.push(JSON.parse(value));
|
|
473
|
+
}
|
|
474
|
+
return matches;
|
|
595
475
|
}
|
|
596
476
|
/**
|
|
597
477
|
* Sorts Items lexicographically in ascending or descending order given a specific indexName, using the messageCid as a tie breaker.
|
|
@@ -639,16 +519,14 @@ export class IndexLevel {
|
|
|
639
519
|
/**
|
|
640
520
|
* Gets the indexes given an messageCid. This is a reverse lookup to construct starting keys, as well as deleting indexed items.
|
|
641
521
|
*/
|
|
642
|
-
getIndexes(tenant, messageCid) {
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
return JSON.parse(serializedIndexes);
|
|
651
|
-
});
|
|
522
|
+
async getIndexes(tenant, messageCid) {
|
|
523
|
+
const indexesLookupPartition = await this.getIndexesLookupPartition(tenant);
|
|
524
|
+
const serializedIndexes = await indexesLookupPartition.get(messageCid);
|
|
525
|
+
if (serializedIndexes === undefined) {
|
|
526
|
+
// invalid messageCid
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
return JSON.parse(serializedIndexes);
|
|
652
530
|
}
|
|
653
531
|
/**
|
|
654
532
|
* Given a key from an indexed partitioned property key.
|
|
@@ -660,6 +538,10 @@ export class IndexLevel {
|
|
|
660
538
|
const [value] = key.split(IndexLevel.delimiter);
|
|
661
539
|
return value;
|
|
662
540
|
}
|
|
541
|
+
/**
|
|
542
|
+
* Joins the given values using the `\x00` (\u0000) character.
|
|
543
|
+
*/
|
|
544
|
+
static delimiter = `\x00`;
|
|
663
545
|
static keySegmentJoin(...values) {
|
|
664
546
|
return values.join(IndexLevel.delimiter);
|
|
665
547
|
}
|
|
@@ -694,292 +576,6 @@ export class IndexLevel {
|
|
|
694
576
|
}
|
|
695
577
|
}
|
|
696
578
|
// =========================================================================
|
|
697
|
-
// Compound index methods
|
|
698
|
-
// =========================================================================
|
|
699
|
-
/**
|
|
700
|
-
* Gets the compound index partition for a given compound index definition.
|
|
701
|
-
* Compound index sublevels use the naming convention `__compound:<name>__`.
|
|
702
|
-
*/
|
|
703
|
-
getCompoundIndexPartition(tenant, compoundIndex) {
|
|
704
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
705
|
-
const partitionName = `__compound:${compoundIndex.name}__`;
|
|
706
|
-
return (yield this.db.partition(tenant)).partition(partitionName);
|
|
707
|
-
});
|
|
708
|
-
}
|
|
709
|
-
/**
|
|
710
|
-
* Builds a compound index key from the given indexes and compound index definition.
|
|
711
|
-
*
|
|
712
|
-
* Key format: `<prop1>\x01<prop2>\x01...\x01<sortValue>\x00<messageCid>`
|
|
713
|
-
*
|
|
714
|
-
* @returns the compound key, or undefined if the indexes don't contain all required properties.
|
|
715
|
-
*/
|
|
716
|
-
static buildCompoundKey(messageCid, indexes, compoundIndex) {
|
|
717
|
-
const segments = [];
|
|
718
|
-
for (const property of compoundIndex.properties) {
|
|
719
|
-
const value = indexes[property];
|
|
720
|
-
if (value === undefined || Array.isArray(value)) {
|
|
721
|
-
return undefined; // compound indexes don't support array values or missing properties
|
|
722
|
-
}
|
|
723
|
-
segments.push(IndexLevel.encodeValue(value));
|
|
724
|
-
}
|
|
725
|
-
const sortValue = indexes[compoundIndex.sortProperty];
|
|
726
|
-
if (sortValue === undefined || Array.isArray(sortValue)) {
|
|
727
|
-
return undefined;
|
|
728
|
-
}
|
|
729
|
-
// join prefix segments with \x01, then append sort value and messageCid with the standard delimiters
|
|
730
|
-
const prefixPart = segments.join(COMPOUND_SEGMENT_SEPARATOR);
|
|
731
|
-
const sortPart = IndexLevel.encodeValue(sortValue);
|
|
732
|
-
return prefixPart + COMPOUND_SEGMENT_SEPARATOR + sortPart + IndexLevel.delimiter + messageCid;
|
|
733
|
-
}
|
|
734
|
-
/**
|
|
735
|
-
* Builds the prefix portion of a compound key from filter values (without the sort/messageCid suffix).
|
|
736
|
-
* Used for range scans: all entries with this prefix match the filter.
|
|
737
|
-
*/
|
|
738
|
-
static buildCompoundPrefix(filter, compoundIndex) {
|
|
739
|
-
const segments = [];
|
|
740
|
-
for (const property of compoundIndex.properties) {
|
|
741
|
-
const filterValue = filter[property];
|
|
742
|
-
if (filterValue === undefined || typeof filterValue === 'object') {
|
|
743
|
-
return undefined; // compound prefix only works with equality filters
|
|
744
|
-
}
|
|
745
|
-
segments.push(IndexLevel.encodeValue(filterValue));
|
|
746
|
-
}
|
|
747
|
-
return segments.join(COMPOUND_SEGMENT_SEPARATOR) + COMPOUND_SEGMENT_SEPARATOR;
|
|
748
|
-
}
|
|
749
|
-
/**
|
|
750
|
-
* Creates a put operation for a compound index entry.
|
|
751
|
-
* Returns undefined if the indexes don't contain all required compound index properties.
|
|
752
|
-
*/
|
|
753
|
-
createCompoundIndexPutOperation(tenant, item, compoundIndex) {
|
|
754
|
-
const key = IndexLevel.buildCompoundKey(item.messageCid, item.indexes, compoundIndex);
|
|
755
|
-
if (key === undefined) {
|
|
756
|
-
return undefined;
|
|
757
|
-
}
|
|
758
|
-
return this.createOperationForPartition(tenant, `__compound:${compoundIndex.name}__`, {
|
|
759
|
-
type: 'put',
|
|
760
|
-
key,
|
|
761
|
-
value: JSON.stringify(item),
|
|
762
|
-
});
|
|
763
|
-
}
|
|
764
|
-
/**
|
|
765
|
-
* Creates a delete operation for a compound index entry.
|
|
766
|
-
* Returns undefined if the indexes don't contain all required compound index properties.
|
|
767
|
-
*/
|
|
768
|
-
createCompoundIndexDeleteOperation(tenant, messageCid, indexes, compoundIndex) {
|
|
769
|
-
const key = IndexLevel.buildCompoundKey(messageCid, indexes, compoundIndex);
|
|
770
|
-
if (key === undefined) {
|
|
771
|
-
return undefined;
|
|
772
|
-
}
|
|
773
|
-
return this.createOperationForPartition(tenant, `__compound:${compoundIndex.name}__`, {
|
|
774
|
-
type: 'del',
|
|
775
|
-
key,
|
|
776
|
-
});
|
|
777
|
-
}
|
|
778
|
-
/**
|
|
779
|
-
* Generic helper to create a batch operation for any named partition under a tenant.
|
|
780
|
-
*/
|
|
781
|
-
createOperationForPartition(tenant, partitionName, operation) {
|
|
782
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
783
|
-
const tenantPartition = yield this.db.partition(tenant);
|
|
784
|
-
return tenantPartition.createPartitionOperation(partitionName, operation);
|
|
785
|
-
});
|
|
786
|
-
}
|
|
787
|
-
/**
|
|
788
|
-
* Selects the best compound index that covers the given filter and sort requirements.
|
|
789
|
-
*
|
|
790
|
-
* A compound index "covers" a query when:
|
|
791
|
-
* 1. Every property in the compound index definition is present in the filter as an equality filter.
|
|
792
|
-
* 2. The compound index's sort property matches the query's sort property.
|
|
793
|
-
*
|
|
794
|
-
* Among multiple matching compound indexes, the one with the most properties is preferred
|
|
795
|
-
* (more specific = fewer false positives in the prefix scan).
|
|
796
|
-
*/
|
|
797
|
-
selectCompoundIndex(filter, queryOptions) {
|
|
798
|
-
let bestMatch;
|
|
799
|
-
let bestPropertyCount = 0;
|
|
800
|
-
for (const compoundIndex of this._compoundIndexes) {
|
|
801
|
-
// check that the sort property matches
|
|
802
|
-
if (compoundIndex.sortProperty !== queryOptions.sortProperty) {
|
|
803
|
-
continue;
|
|
804
|
-
}
|
|
805
|
-
// check that all compound properties are present in the filter as equality filters
|
|
806
|
-
let allPropertiesMatch = true;
|
|
807
|
-
for (const property of compoundIndex.properties) {
|
|
808
|
-
const filterValue = filter[property];
|
|
809
|
-
if (filterValue === undefined || typeof filterValue === 'object') {
|
|
810
|
-
allPropertiesMatch = false;
|
|
811
|
-
break;
|
|
812
|
-
}
|
|
813
|
-
}
|
|
814
|
-
if (allPropertiesMatch && compoundIndex.properties.length > bestPropertyCount) {
|
|
815
|
-
bestMatch = compoundIndex;
|
|
816
|
-
bestPropertyCount = compoundIndex.properties.length;
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
|
-
return bestMatch;
|
|
820
|
-
}
|
|
821
|
-
/**
|
|
822
|
-
* Queries using a compound index. This is the most efficient query strategy: a single LevelDB
|
|
823
|
-
* range scan that filters, sorts, and paginates all at once.
|
|
824
|
-
*
|
|
825
|
-
* The compound key encodes the filter properties as a prefix and the sort property as a suffix,
|
|
826
|
-
* so iterating over keys with the filter prefix yields results in sort order.
|
|
827
|
-
*
|
|
828
|
-
* Any remaining filter properties not covered by the compound index are verified in memory.
|
|
829
|
-
*/
|
|
830
|
-
queryWithCompoundIndex(tenant, filter, queryOptions, compoundIndex, options) {
|
|
831
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
832
|
-
var _a, e_6, _b, _c;
|
|
833
|
-
const { sortDirection = SortDirection.Ascending, cursor, limit } = queryOptions;
|
|
834
|
-
const prefix = IndexLevel.buildCompoundPrefix(filter, compoundIndex);
|
|
835
|
-
if (prefix === undefined) {
|
|
836
|
-
// should not happen since selectCompoundIndex already validated, but guard against it
|
|
837
|
-
return this.queryWithIteratorPaging(tenant, [filter], queryOptions, options);
|
|
838
|
-
}
|
|
839
|
-
const partition = yield this.getCompoundIndexPartition(tenant, compoundIndex);
|
|
840
|
-
// determine the iterator bounds from the prefix
|
|
841
|
-
const iteratorOptions = {};
|
|
842
|
-
if (cursor !== undefined) {
|
|
843
|
-
// build the full compound key for the cursor position
|
|
844
|
-
const cursorSortEncoded = IndexLevel.encodeValue(cursor.value);
|
|
845
|
-
const cursorKey = prefix + cursorSortEncoded + IndexLevel.delimiter + cursor.messageCid;
|
|
846
|
-
if (sortDirection === SortDirection.Ascending) {
|
|
847
|
-
iteratorOptions.gt = cursorKey;
|
|
848
|
-
// upper bound: everything with this prefix (prefix + \xff is past all valid compound keys with this prefix)
|
|
849
|
-
iteratorOptions.lt = prefix + '\xff';
|
|
850
|
-
}
|
|
851
|
-
else {
|
|
852
|
-
iteratorOptions.lt = cursorKey;
|
|
853
|
-
iteratorOptions.gt = prefix;
|
|
854
|
-
iteratorOptions.reverse = true;
|
|
855
|
-
}
|
|
856
|
-
}
|
|
857
|
-
else {
|
|
858
|
-
if (sortDirection === SortDirection.Ascending) {
|
|
859
|
-
iteratorOptions.gt = prefix;
|
|
860
|
-
iteratorOptions.lt = prefix + '\xff';
|
|
861
|
-
}
|
|
862
|
-
else {
|
|
863
|
-
// for descending without cursor, start from the end of the prefix range
|
|
864
|
-
iteratorOptions.gt = prefix;
|
|
865
|
-
iteratorOptions.lt = prefix + '\xff';
|
|
866
|
-
iteratorOptions.reverse = true;
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
// determine which filter properties are NOT covered by the compound index
|
|
870
|
-
// (need in-memory verification for these)
|
|
871
|
-
// NOTE: the compound index equality properties are fully covered by the prefix scan,
|
|
872
|
-
// but the sort property is only covered for ordering — any range filter on the sort
|
|
873
|
-
// property must still be applied as a residual filter.
|
|
874
|
-
const coveredEqualityProperties = new Set(compoundIndex.properties);
|
|
875
|
-
const residualFilter = {};
|
|
876
|
-
let hasResidualFilter = false;
|
|
877
|
-
for (const property in filter) {
|
|
878
|
-
if (!coveredEqualityProperties.has(property)) {
|
|
879
|
-
residualFilter[property] = filter[property];
|
|
880
|
-
hasResidualFilter = true;
|
|
881
|
-
}
|
|
882
|
-
}
|
|
883
|
-
const matches = [];
|
|
884
|
-
try {
|
|
885
|
-
for (var _d = true, _e = __asyncValues(partition.iterator(iteratorOptions, options)), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
|
|
886
|
-
_c = _f.value;
|
|
887
|
-
_d = false;
|
|
888
|
-
const [_key, value] = _c;
|
|
889
|
-
if (limit !== undefined && matches.length === limit) {
|
|
890
|
-
break;
|
|
891
|
-
}
|
|
892
|
-
const item = JSON.parse(value);
|
|
893
|
-
// verify any residual filter properties in memory
|
|
894
|
-
if (hasResidualFilter && !FilterUtility.matchFilter(item.indexes, residualFilter)) {
|
|
895
|
-
continue;
|
|
896
|
-
}
|
|
897
|
-
matches.push(item);
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
catch (e_6_1) { e_6 = { error: e_6_1 }; }
|
|
901
|
-
finally {
|
|
902
|
-
try {
|
|
903
|
-
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
904
|
-
}
|
|
905
|
-
finally { if (e_6) throw e_6.error; }
|
|
906
|
-
}
|
|
907
|
-
return matches;
|
|
908
|
-
});
|
|
909
|
-
}
|
|
910
|
-
/**
|
|
911
|
-
* Counts items matching a compound index prefix without loading full records.
|
|
912
|
-
* Iterates only keys (not values) for maximum efficiency.
|
|
913
|
-
*/
|
|
914
|
-
countWithCompoundIndex(tenant, filter, compoundIndex, options) {
|
|
915
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
916
|
-
var _a, e_7, _b, _c, _d, e_8, _e, _f;
|
|
917
|
-
const prefix = IndexLevel.buildCompoundPrefix(filter, compoundIndex);
|
|
918
|
-
if (prefix === undefined) {
|
|
919
|
-
// fallback
|
|
920
|
-
const results = yield this.query(tenant, [filter], { sortProperty: compoundIndex.sortProperty }, options);
|
|
921
|
-
return results.length;
|
|
922
|
-
}
|
|
923
|
-
const partition = yield this.getCompoundIndexPartition(tenant, compoundIndex);
|
|
924
|
-
// determine which filter properties are NOT covered by the compound index
|
|
925
|
-
// (same logic as queryWithCompoundIndex: sort property range filters are residual)
|
|
926
|
-
const coveredEqualityProperties = new Set(compoundIndex.properties);
|
|
927
|
-
let hasResidualFilter = false;
|
|
928
|
-
const residualFilter = {};
|
|
929
|
-
for (const property in filter) {
|
|
930
|
-
if (!coveredEqualityProperties.has(property)) {
|
|
931
|
-
residualFilter[property] = filter[property];
|
|
932
|
-
hasResidualFilter = true;
|
|
933
|
-
}
|
|
934
|
-
}
|
|
935
|
-
const iteratorOptions = {
|
|
936
|
-
gt: prefix,
|
|
937
|
-
lt: prefix + '\xff',
|
|
938
|
-
};
|
|
939
|
-
let count = 0;
|
|
940
|
-
if (hasResidualFilter) {
|
|
941
|
-
try {
|
|
942
|
-
// must read values to check residual filter
|
|
943
|
-
for (var _g = true, _h = __asyncValues(partition.iterator(iteratorOptions, options)), _j; _j = yield _h.next(), _a = _j.done, !_a; _g = true) {
|
|
944
|
-
_c = _j.value;
|
|
945
|
-
_g = false;
|
|
946
|
-
const [_key, value] = _c;
|
|
947
|
-
const item = JSON.parse(value);
|
|
948
|
-
if (FilterUtility.matchFilter(item.indexes, residualFilter)) {
|
|
949
|
-
count++;
|
|
950
|
-
}
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
catch (e_7_1) { e_7 = { error: e_7_1 }; }
|
|
954
|
-
finally {
|
|
955
|
-
try {
|
|
956
|
-
if (!_g && !_a && (_b = _h.return)) yield _b.call(_h);
|
|
957
|
-
}
|
|
958
|
-
finally { if (e_7) throw e_7.error; }
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
else {
|
|
962
|
-
try {
|
|
963
|
-
// no residual filter — iterate keys via iterator without parsing values
|
|
964
|
-
for (var _k = true, _l = __asyncValues(partition.iterator(iteratorOptions, options)), _m; _m = yield _l.next(), _d = _m.done, !_d; _k = true) {
|
|
965
|
-
_f = _m.value;
|
|
966
|
-
_k = false;
|
|
967
|
-
const [_key, _value] = _f;
|
|
968
|
-
count++;
|
|
969
|
-
}
|
|
970
|
-
}
|
|
971
|
-
catch (e_8_1) { e_8 = { error: e_8_1 }; }
|
|
972
|
-
finally {
|
|
973
|
-
try {
|
|
974
|
-
if (!_k && !_d && (_e = _l.return)) yield _e.call(_l);
|
|
975
|
-
}
|
|
976
|
-
finally { if (e_8) throw e_8.error; }
|
|
977
|
-
}
|
|
978
|
-
}
|
|
979
|
-
return count;
|
|
980
|
-
});
|
|
981
|
-
}
|
|
982
|
-
// =========================================================================
|
|
983
579
|
// Query strategy selection
|
|
984
580
|
// =========================================================================
|
|
985
581
|
static shouldQueryWithInMemoryPaging(filters, queryOptions) {
|
|
@@ -1011,8 +607,4 @@ export class IndexLevel {
|
|
|
1011
607
|
return false;
|
|
1012
608
|
}
|
|
1013
609
|
}
|
|
1014
|
-
/**
|
|
1015
|
-
* Joins the given values using the `\x00` (\u0000) character.
|
|
1016
|
-
*/
|
|
1017
|
-
IndexLevel.delimiter = `\x00`;
|
|
1018
610
|
//# sourceMappingURL=index-level.js.map
|