@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,12 +1,3 @@
|
|
|
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
1
|
import { ArrayUtility } from '../../src/utils/array.js';
|
|
11
2
|
import { createLevelDatabase } from '../../src/store/level-wrapper.js';
|
|
12
3
|
import { DwnErrorCode } from '../../src/index.js';
|
|
@@ -21,59 +12,59 @@ describe('IndexLevel', () => {
|
|
|
21
12
|
let testIndex;
|
|
22
13
|
const tenant = 'did:alice:index-test';
|
|
23
14
|
describe('put', () => {
|
|
24
|
-
beforeAll(() =>
|
|
15
|
+
beforeAll(async () => {
|
|
25
16
|
testIndex = new IndexLevel({
|
|
26
17
|
createLevelDatabase,
|
|
27
18
|
location: 'TEST-INDEX',
|
|
28
19
|
});
|
|
29
|
-
|
|
30
|
-
})
|
|
31
|
-
beforeEach(() =>
|
|
32
|
-
|
|
33
|
-
})
|
|
34
|
-
afterAll(() =>
|
|
35
|
-
|
|
36
|
-
})
|
|
20
|
+
await testIndex.open();
|
|
21
|
+
});
|
|
22
|
+
beforeEach(async () => {
|
|
23
|
+
await testIndex.clear();
|
|
24
|
+
});
|
|
25
|
+
afterAll(async () => {
|
|
26
|
+
await testIndex.close();
|
|
27
|
+
});
|
|
37
28
|
describe('fails to index with no indexable properties', () => {
|
|
38
|
-
it('fails on empty indexes', () =>
|
|
29
|
+
it('fails on empty indexes', async () => {
|
|
39
30
|
const id = uuid();
|
|
40
31
|
const failedIndexPromise = testIndex.put(tenant, id, {});
|
|
41
|
-
|
|
42
|
-
})
|
|
32
|
+
await expect(failedIndexPromise).rejects.toThrow(DwnErrorCode.IndexMissingIndexableProperty);
|
|
33
|
+
});
|
|
43
34
|
});
|
|
44
|
-
it('successfully indexes', () =>
|
|
35
|
+
it('successfully indexes', async () => {
|
|
45
36
|
const id = uuid();
|
|
46
|
-
|
|
37
|
+
await testIndex.put(tenant, id, {
|
|
47
38
|
id,
|
|
48
39
|
foo: 'foo',
|
|
49
40
|
digit: 12,
|
|
50
41
|
toggle: false,
|
|
51
42
|
tag: ['bar', 'baz']
|
|
52
43
|
});
|
|
53
|
-
const results =
|
|
44
|
+
const results = await testIndex.query(tenant, [{ id: id }], { sortProperty: 'id' });
|
|
54
45
|
expect(results[0].messageCid).toBe(id);
|
|
55
|
-
})
|
|
56
|
-
it('adds one index key per property value, aside from id', () =>
|
|
46
|
+
});
|
|
47
|
+
it('adds one index key per property value, aside from id', async () => {
|
|
57
48
|
const id = uuid(); // 1 key for reverse lookup
|
|
58
49
|
const dateCreated = new Date().toISOString();
|
|
59
|
-
|
|
50
|
+
await testIndex.put(tenant, id, {
|
|
60
51
|
'a': 'b', // 1 key
|
|
61
52
|
'c': ['d', 'e'], // 2 key
|
|
62
53
|
dateCreated, // 1 key
|
|
63
54
|
});
|
|
64
|
-
let keys =
|
|
55
|
+
let keys = await ArrayUtility.fromAsyncGenerator(testIndex.db.keys());
|
|
65
56
|
expect(keys.length).toBe(5);
|
|
66
|
-
|
|
67
|
-
|
|
57
|
+
await testIndex.clear();
|
|
58
|
+
await testIndex.put(tenant, id, {
|
|
68
59
|
'a': 'b', // 1 key
|
|
69
60
|
'c': ['d', 'e'], // 2 keys
|
|
70
61
|
'f': 'g', // 1 key
|
|
71
62
|
dateCreated, // 1 key
|
|
72
63
|
});
|
|
73
|
-
keys =
|
|
64
|
+
keys = await ArrayUtility.fromAsyncGenerator(testIndex.db.keys());
|
|
74
65
|
expect(keys.length).toBe(6);
|
|
75
|
-
})
|
|
76
|
-
it('should not put anything if aborted beforehand', () =>
|
|
66
|
+
});
|
|
67
|
+
it('should not put anything if aborted beforehand', async () => {
|
|
77
68
|
const controller = new AbortController();
|
|
78
69
|
controller.abort('reason');
|
|
79
70
|
const id = uuid();
|
|
@@ -82,26 +73,26 @@ describe('IndexLevel', () => {
|
|
|
82
73
|
foo: 'bar'
|
|
83
74
|
};
|
|
84
75
|
const indexPromise = testIndex.put(tenant, id, index, { signal: controller.signal });
|
|
85
|
-
|
|
86
|
-
const entries =
|
|
76
|
+
await expect(indexPromise).rejects.toThrow('reason');
|
|
77
|
+
const entries = await testIndex.query(tenant, [{ foo: 'bar' }], { sortProperty: 'id' });
|
|
87
78
|
expect(entries.length).toBe(0);
|
|
88
|
-
})
|
|
79
|
+
});
|
|
89
80
|
});
|
|
90
81
|
describe('query', () => {
|
|
91
|
-
beforeAll(() =>
|
|
82
|
+
beforeAll(async () => {
|
|
92
83
|
testIndex = new IndexLevel({
|
|
93
84
|
createLevelDatabase,
|
|
94
85
|
location: 'TEST-INDEX',
|
|
95
86
|
});
|
|
96
|
-
|
|
97
|
-
})
|
|
98
|
-
beforeEach(() =>
|
|
99
|
-
|
|
100
|
-
})
|
|
101
|
-
afterAll(() =>
|
|
102
|
-
|
|
103
|
-
})
|
|
104
|
-
it('works', () =>
|
|
87
|
+
await testIndex.open();
|
|
88
|
+
});
|
|
89
|
+
beforeEach(async () => {
|
|
90
|
+
await testIndex.clear();
|
|
91
|
+
});
|
|
92
|
+
afterAll(async () => {
|
|
93
|
+
await testIndex.close();
|
|
94
|
+
});
|
|
95
|
+
it('works', async () => {
|
|
105
96
|
const id1 = uuid();
|
|
106
97
|
const doc1 = {
|
|
107
98
|
id: id1,
|
|
@@ -120,106 +111,106 @@ describe('IndexLevel', () => {
|
|
|
120
111
|
'a': 'b',
|
|
121
112
|
'c': 'e'
|
|
122
113
|
};
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
const entries =
|
|
114
|
+
await testIndex.put(tenant, id1, doc1);
|
|
115
|
+
await testIndex.put(tenant, id2, doc2);
|
|
116
|
+
await testIndex.put(tenant, id3, doc3);
|
|
117
|
+
const entries = await testIndex.query(tenant, [{
|
|
127
118
|
'a': 'b',
|
|
128
119
|
'c': 'e'
|
|
129
120
|
}], { sortProperty: 'id' });
|
|
130
121
|
expect(entries.length).toBe(1);
|
|
131
122
|
expect(entries[0].messageCid).toBe(id3);
|
|
132
|
-
})
|
|
133
|
-
it('should return all records if an empty filter array is passed', () =>
|
|
123
|
+
});
|
|
124
|
+
it('should return all records if an empty filter array is passed', async () => {
|
|
134
125
|
const items = ['b', 'a', 'd', 'c'];
|
|
135
126
|
for (const item of items) {
|
|
136
|
-
|
|
127
|
+
await testIndex.put(tenant, item, { letter: item, index: items.indexOf(item) });
|
|
137
128
|
}
|
|
138
129
|
// empty array
|
|
139
|
-
let allResults =
|
|
130
|
+
let allResults = await testIndex.query(tenant, [], { sortProperty: 'letter' });
|
|
140
131
|
expect(allResults.map(({ messageCid }) => messageCid)).toEqual(['a', 'b', 'c', 'd']);
|
|
141
132
|
// empty filter
|
|
142
|
-
allResults =
|
|
133
|
+
allResults = await testIndex.query(tenant, [{}], { sortProperty: 'letter' });
|
|
143
134
|
expect(allResults.map(({ messageCid }) => messageCid)).toEqual(['a', 'b', 'c', 'd']);
|
|
144
|
-
})
|
|
135
|
+
});
|
|
145
136
|
describe('queryWithIteratorPaging()', () => {
|
|
146
|
-
it('paginates using cursor', () =>
|
|
137
|
+
it('paginates using cursor', async () => {
|
|
147
138
|
const testVals = ['b', 'd', 'c', 'a'];
|
|
148
139
|
for (const val of testVals) {
|
|
149
|
-
|
|
140
|
+
await testIndex.put(tenant, val, { val, schema: 'schema', published: true });
|
|
150
141
|
}
|
|
151
142
|
// insert other records to be filtered out
|
|
152
143
|
for (const val of testVals) {
|
|
153
144
|
const otherVal = val + val;
|
|
154
|
-
|
|
145
|
+
await testIndex.put(tenant, otherVal, { val: otherVal, schema: 'schema', published: false });
|
|
155
146
|
}
|
|
156
147
|
const filters = [{ schema: 'schema', published: true }];
|
|
157
148
|
// query with limit, default (ascending)
|
|
158
|
-
const results =
|
|
149
|
+
const results = await testIndex.queryWithIteratorPaging(tenant, filters, { sortProperty: 'val', limit: 2 });
|
|
159
150
|
expect(results.length).toBe(2);
|
|
160
151
|
expect(results.map(({ messageCid }) => messageCid)).toEqual(['a', 'b']);
|
|
161
152
|
// query with cursor, default (ascending)
|
|
162
|
-
const resultsAfterCursor =
|
|
153
|
+
const resultsAfterCursor = await testIndex.queryWithIteratorPaging(tenant, filters, { sortProperty: 'val', cursor: IndexLevel.createCursorFromLastArrayItem(results, 'val') });
|
|
163
154
|
expect(resultsAfterCursor.length).toBe(2);
|
|
164
155
|
expect(resultsAfterCursor.map(({ messageCid }) => messageCid)).toEqual(['c', 'd']);
|
|
165
156
|
// query with limit, explicit ascending
|
|
166
|
-
const ascResults =
|
|
157
|
+
const ascResults = await testIndex.queryWithIteratorPaging(tenant, filters, { sortProperty: 'val', limit: 2 });
|
|
167
158
|
expect(ascResults.length).toBe(2);
|
|
168
159
|
expect(ascResults.map(({ messageCid }) => messageCid)).toEqual(['a', 'b']);
|
|
169
160
|
// query with cursor, explicit ascending
|
|
170
|
-
const ascResultsAfterCursor =
|
|
161
|
+
const ascResultsAfterCursor = await testIndex.queryWithIteratorPaging(tenant, filters, { sortProperty: 'val', cursor: IndexLevel.createCursorFromLastArrayItem(ascResults, 'val') });
|
|
171
162
|
expect(ascResultsAfterCursor.length).toBe(2);
|
|
172
163
|
expect(ascResultsAfterCursor.map(({ messageCid }) => messageCid)).toEqual(['c', 'd']);
|
|
173
164
|
// query with limit, descending
|
|
174
|
-
const descResults =
|
|
165
|
+
const descResults = await testIndex.queryWithIteratorPaging(tenant, filters, { sortDirection: SortDirection.Descending, sortProperty: 'val', limit: 2 });
|
|
175
166
|
expect(descResults.length).toBe(2);
|
|
176
167
|
expect(descResults.map(({ messageCid }) => messageCid)).toEqual(['d', 'c']);
|
|
177
168
|
// query with cursor, descending
|
|
178
|
-
const descResultsAfterCursor =
|
|
169
|
+
const descResultsAfterCursor = await testIndex.queryWithIteratorPaging(tenant, filters, { sortDirection: SortDirection.Descending, sortProperty: 'val', cursor: IndexLevel.createCursorFromLastArrayItem(descResults, 'val') });
|
|
179
170
|
expect(descResultsAfterCursor.length).toBe(2);
|
|
180
171
|
expect(descResultsAfterCursor.map(({ messageCid }) => messageCid)).toEqual(['b', 'a']);
|
|
181
|
-
})
|
|
182
|
-
it('returns empty array if sort property is invalid', () =>
|
|
172
|
+
});
|
|
173
|
+
it('returns empty array if sort property is invalid', async () => {
|
|
183
174
|
const testVals = ['b', 'd', 'c', 'a'];
|
|
184
175
|
for (const val of testVals) {
|
|
185
|
-
|
|
176
|
+
await testIndex.put(tenant, val, { val, schema: 'schema', published: true });
|
|
186
177
|
}
|
|
187
178
|
// insert other records to be filtered out
|
|
188
179
|
for (const val of testVals) {
|
|
189
180
|
const otherVal = val + val;
|
|
190
|
-
|
|
181
|
+
await testIndex.put(tenant, otherVal, { val: otherVal, schema: 'schema', published: false });
|
|
191
182
|
}
|
|
192
183
|
const filters = [{ schema: 'schema', published: true }];
|
|
193
184
|
// control test: return all results
|
|
194
|
-
const validResults =
|
|
185
|
+
const validResults = await testIndex.queryWithIteratorPaging(tenant, filters, { sortProperty: 'val' });
|
|
195
186
|
expect(validResults.length).toBe(4);
|
|
196
187
|
// sort by invalid property returns no results
|
|
197
|
-
const invalidResults =
|
|
188
|
+
const invalidResults = await testIndex.queryWithIteratorPaging(tenant, filters, { sortProperty: 'invalid' });
|
|
198
189
|
expect(invalidResults.length).toBe(0);
|
|
199
|
-
})
|
|
200
|
-
it('cursor is valid but out of range of matched results', () =>
|
|
190
|
+
});
|
|
191
|
+
it('cursor is valid but out of range of matched results', async () => {
|
|
201
192
|
const testVals = ['b', 'd', 'c']; // a is missing
|
|
202
193
|
for (const val of testVals) {
|
|
203
|
-
|
|
194
|
+
await testIndex.put(tenant, `${val}-id`, { val, schema: 'schema', published: true });
|
|
204
195
|
}
|
|
205
196
|
// insert other records to be filtered out
|
|
206
197
|
for (const val of testVals) {
|
|
207
198
|
const otherVal = val + val;
|
|
208
|
-
|
|
199
|
+
await testIndex.put(tenant, `${val}-id`, { val: otherVal, schema: 'schema', published: false });
|
|
209
200
|
}
|
|
210
201
|
const filters = [{ schema: 'schema', published: true }];
|
|
211
202
|
// cursor `a-id` doesn't actually exist, but the value `a` is sorted prior to the result set.
|
|
212
203
|
const cursorA = { messageCid: 'a-id', value: 'a' };
|
|
213
|
-
const allResults =
|
|
204
|
+
const allResults = await testIndex.queryWithIteratorPaging(tenant, filters, { sortProperty: 'val', cursor: cursorA });
|
|
214
205
|
expect(allResults.map(({ messageCid }) => messageCid)).toEqual(['b-id', 'c-id', 'd-id']);
|
|
215
206
|
// cursor `e-id` doesn't actually exist, but the value `e` is sorted after to the result set.
|
|
216
207
|
const cursorE = { messageCid: 'e-id', value: 'e' };
|
|
217
|
-
const noResults =
|
|
208
|
+
const noResults = await testIndex.queryWithIteratorPaging(tenant, filters, { sortProperty: 'val', cursor: cursorE });
|
|
218
209
|
expect(noResults.length).toEqual(0);
|
|
219
|
-
})
|
|
210
|
+
});
|
|
220
211
|
});
|
|
221
212
|
describe('array values', () => {
|
|
222
|
-
it('query items with string array values', () =>
|
|
213
|
+
it('query items with string array values', async () => {
|
|
223
214
|
const items = [{
|
|
224
215
|
id: uuid(),
|
|
225
216
|
tag: ['item1', 'item']
|
|
@@ -234,18 +225,18 @@ describe('IndexLevel', () => {
|
|
|
234
225
|
tag: ['item4', 'item']
|
|
235
226
|
}];
|
|
236
227
|
for (const item of items) {
|
|
237
|
-
|
|
228
|
+
await testIndex.put(tenant, item.id, item);
|
|
238
229
|
}
|
|
239
230
|
const filterForItemTag = [{ tag: 'item' }];
|
|
240
|
-
const allResults =
|
|
231
|
+
const allResults = await testIndex.queryWithIteratorPaging(tenant, filterForItemTag, { sortProperty: 'id' });
|
|
241
232
|
expect(allResults.length).toBe(4);
|
|
242
233
|
expect(allResults.map(item => item.messageCid)).toEqual(expect.arrayContaining(items.map(item => item.id)));
|
|
243
234
|
const filterForItem3 = [{ tag: 'item3' }];
|
|
244
|
-
const item3Results =
|
|
235
|
+
const item3Results = await testIndex.queryWithIteratorPaging(tenant, filterForItem3, { sortProperty: 'id' });
|
|
245
236
|
expect(item3Results.length).toBe(1);
|
|
246
237
|
expect(item3Results.map(item => item.messageCid)).toEqual(expect.arrayContaining([items[2].id]));
|
|
247
|
-
})
|
|
248
|
-
it('query items with number array values', () =>
|
|
238
|
+
});
|
|
239
|
+
it('query items with number array values', async () => {
|
|
249
240
|
const items = [{
|
|
250
241
|
id: uuid(),
|
|
251
242
|
tag: [1]
|
|
@@ -260,121 +251,121 @@ describe('IndexLevel', () => {
|
|
|
260
251
|
tag: [1, 4]
|
|
261
252
|
}];
|
|
262
253
|
for (const item of items) {
|
|
263
|
-
|
|
254
|
+
await testIndex.put(tenant, item.id, item);
|
|
264
255
|
}
|
|
265
256
|
const filterForItemTag = [{ tag: 1 }];
|
|
266
|
-
const allResults =
|
|
257
|
+
const allResults = await testIndex.queryWithIteratorPaging(tenant, filterForItemTag, { sortProperty: 'id' });
|
|
267
258
|
expect(allResults.length).toBe(4);
|
|
268
259
|
expect(allResults.map(item => item.messageCid)).toEqual(expect.arrayContaining(items.map(item => item.id)));
|
|
269
260
|
const filterForItem3 = [{ tag: 3 }];
|
|
270
|
-
const item3Results =
|
|
261
|
+
const item3Results = await testIndex.queryWithIteratorPaging(tenant, filterForItem3, { sortProperty: 'id' });
|
|
271
262
|
expect(item3Results.length).toBe(1);
|
|
272
263
|
expect(item3Results.map(item => item.messageCid)).toEqual(expect.arrayContaining([items[2].id]));
|
|
273
264
|
const filterForRange = [{ tag: { gt: 1, lt: 4 } }];
|
|
274
|
-
const rangeItems =
|
|
265
|
+
const rangeItems = await testIndex.queryWithIteratorPaging(tenant, filterForRange, { sortProperty: 'id' });
|
|
275
266
|
expect(rangeItems.length).toBe(2);
|
|
276
267
|
expect(rangeItems.map(item => item.messageCid)).toEqual(expect.arrayContaining([items[1].id, items[2].id]));
|
|
277
|
-
})
|
|
268
|
+
});
|
|
278
269
|
});
|
|
279
270
|
describe('queryWithInMemoryPaging()', () => {
|
|
280
|
-
it('paginates using cursor', () =>
|
|
271
|
+
it('paginates using cursor', async () => {
|
|
281
272
|
const testVals = ['b', 'd', 'c', 'a'];
|
|
282
273
|
for (const val of testVals) {
|
|
283
|
-
|
|
274
|
+
await testIndex.put(tenant, val, { val, schema: 'schema', published: true });
|
|
284
275
|
}
|
|
285
276
|
// insert other records to be filtered out
|
|
286
277
|
for (const val of testVals) {
|
|
287
278
|
const otherVal = val + val;
|
|
288
|
-
|
|
279
|
+
await testIndex.put(tenant, otherVal, { val: otherVal, schema: 'schema', published: false });
|
|
289
280
|
}
|
|
290
281
|
const filters = [{ schema: 'schema', published: true }];
|
|
291
282
|
// query with limit, default (ascending)
|
|
292
|
-
const results =
|
|
283
|
+
const results = await testIndex.queryWithInMemoryPaging(tenant, filters, { sortProperty: 'val', limit: 2 });
|
|
293
284
|
expect(results.length).toBe(2);
|
|
294
285
|
expect(results.map(({ messageCid }) => messageCid)).toEqual(['a', 'b']);
|
|
295
286
|
// query with cursor, default (ascending)
|
|
296
|
-
const resultsAfterCursor =
|
|
287
|
+
const resultsAfterCursor = await testIndex.queryWithInMemoryPaging(tenant, filters, { sortProperty: 'val', cursor: IndexLevel.createCursorFromLastArrayItem(results, 'val') });
|
|
297
288
|
expect(resultsAfterCursor.length).toBe(2);
|
|
298
289
|
expect(resultsAfterCursor.map(({ messageCid }) => messageCid)).toEqual(['c', 'd']);
|
|
299
290
|
// query with limit, explicit ascending
|
|
300
|
-
const ascResults =
|
|
291
|
+
const ascResults = await testIndex.queryWithInMemoryPaging(tenant, filters, { sortProperty: 'val', limit: 2 });
|
|
301
292
|
expect(ascResults.length).toBe(2);
|
|
302
293
|
expect(ascResults.map(({ messageCid }) => messageCid)).toEqual(['a', 'b']);
|
|
303
294
|
// query with cursor, explicit ascending
|
|
304
|
-
const ascResultsAfterCursor =
|
|
295
|
+
const ascResultsAfterCursor = await testIndex.queryWithInMemoryPaging(tenant, filters, { sortProperty: 'val', cursor: IndexLevel.createCursorFromLastArrayItem(ascResults, 'val') });
|
|
305
296
|
expect(ascResultsAfterCursor.length).toBe(2);
|
|
306
297
|
expect(ascResultsAfterCursor.map(({ messageCid }) => messageCid)).toEqual(['c', 'd']);
|
|
307
298
|
// query with limit, descending
|
|
308
|
-
const descResults =
|
|
299
|
+
const descResults = await testIndex.queryWithInMemoryPaging(tenant, filters, { sortDirection: SortDirection.Descending, sortProperty: 'val', limit: 2 });
|
|
309
300
|
expect(descResults.length).toBe(2);
|
|
310
301
|
expect(descResults.map(({ messageCid }) => messageCid)).toEqual(['d', 'c']);
|
|
311
302
|
// query with cursor, descending
|
|
312
|
-
const descResultsAfterCursor =
|
|
303
|
+
const descResultsAfterCursor = await testIndex.queryWithInMemoryPaging(tenant, filters, { sortDirection: SortDirection.Descending, sortProperty: 'val', cursor: IndexLevel.createCursorFromLastArrayItem(descResults, 'val') });
|
|
313
304
|
expect(descResultsAfterCursor.length).toBe(2);
|
|
314
305
|
expect(descResultsAfterCursor.map(({ messageCid }) => messageCid)).toEqual(['b', 'a']);
|
|
315
|
-
})
|
|
316
|
-
it('returns empty array if sort property is invalid', () =>
|
|
306
|
+
});
|
|
307
|
+
it('returns empty array if sort property is invalid', async () => {
|
|
317
308
|
const testVals = ['b', 'd', 'c', 'a'];
|
|
318
309
|
for (const val of testVals) {
|
|
319
|
-
|
|
310
|
+
await testIndex.put(tenant, val, { val, schema: 'schema', published: true });
|
|
320
311
|
}
|
|
321
312
|
// insert other records to be filtered out
|
|
322
313
|
for (const val of testVals) {
|
|
323
314
|
const otherVal = val + val;
|
|
324
|
-
|
|
315
|
+
await testIndex.put(tenant, otherVal, { val: otherVal, schema: 'schema', published: false });
|
|
325
316
|
}
|
|
326
317
|
const filters = [{ schema: 'schema', published: true }];
|
|
327
318
|
// control test: return all results
|
|
328
|
-
const validResults =
|
|
319
|
+
const validResults = await testIndex.queryWithInMemoryPaging(tenant, filters, { sortProperty: 'val', limit: 3 });
|
|
329
320
|
expect(validResults.length).toBe(3);
|
|
330
321
|
// sort by invalid property returns no results
|
|
331
|
-
const invalidResults =
|
|
322
|
+
const invalidResults = await testIndex.queryWithInMemoryPaging(tenant, filters, { sortProperty: 'invalid' });
|
|
332
323
|
expect(invalidResults.length).toBe(0);
|
|
333
|
-
})
|
|
334
|
-
it('cursor is valid but out of range of matched results', () =>
|
|
324
|
+
});
|
|
325
|
+
it('cursor is valid but out of range of matched results', async () => {
|
|
335
326
|
const testVals = ['b', 'd', 'c', 'a'];
|
|
336
327
|
for (const val of testVals) {
|
|
337
|
-
|
|
328
|
+
await testIndex.put(tenant, val, { val, schema: 'schema', published: true });
|
|
338
329
|
}
|
|
339
330
|
// insert other records to be filtered out
|
|
340
331
|
for (const val of testVals) {
|
|
341
332
|
const otherVal = val + val;
|
|
342
|
-
|
|
333
|
+
await testIndex.put(tenant, otherVal, { val: otherVal, schema: 'schema', published: false });
|
|
343
334
|
}
|
|
344
335
|
const filters = [{ schema: 'schema', published: true }];
|
|
345
336
|
const cursorA = { messageCid: 'a', value: 'a' }; // before results
|
|
346
|
-
const allResults =
|
|
337
|
+
const allResults = await testIndex.queryWithInMemoryPaging(tenant, filters, { sortProperty: 'val', cursor: cursorA });
|
|
347
338
|
expect(allResults.map(({ messageCid }) => messageCid)).toEqual(['b', 'c', 'd']);
|
|
348
339
|
const cursorE = { messageCid: 'e', value: 'e' }; // after results
|
|
349
|
-
const noResults =
|
|
340
|
+
const noResults = await testIndex.queryWithInMemoryPaging(tenant, filters, { sortProperty: 'val', cursor: cursorE });
|
|
350
341
|
expect(noResults.length).toEqual(0);
|
|
351
|
-
})
|
|
352
|
-
it('supports range queries', () =>
|
|
342
|
+
});
|
|
343
|
+
it('supports range queries', async () => {
|
|
353
344
|
const id = uuid();
|
|
354
345
|
const doc1 = {
|
|
355
346
|
id,
|
|
356
347
|
value: 'foo'
|
|
357
348
|
};
|
|
358
|
-
|
|
349
|
+
await testIndex.put(tenant, id, doc1);
|
|
359
350
|
const id2 = uuid();
|
|
360
351
|
const doc2 = {
|
|
361
352
|
id: id2,
|
|
362
353
|
value: 'foobar'
|
|
363
354
|
};
|
|
364
|
-
|
|
355
|
+
await testIndex.put(tenant, id2, doc2);
|
|
365
356
|
const id3 = uuid();
|
|
366
357
|
const doc3 = {
|
|
367
358
|
id: id3,
|
|
368
359
|
value: 'foobaz'
|
|
369
360
|
};
|
|
370
|
-
|
|
361
|
+
await testIndex.put(tenant, id3, doc3);
|
|
371
362
|
const filters = [{
|
|
372
363
|
value: {
|
|
373
364
|
gt: 'foo',
|
|
374
365
|
lte: 'foobaz'
|
|
375
366
|
}
|
|
376
367
|
}];
|
|
377
|
-
const entries =
|
|
368
|
+
const entries = await testIndex.queryWithInMemoryPaging(tenant, filters, { sortProperty: 'id' });
|
|
378
369
|
expect(entries.length).toBe(2);
|
|
379
370
|
expect(entries.map(({ messageCid }) => messageCid)).toEqual(expect.arrayContaining([id2, id3]));
|
|
380
371
|
// only upper bounds
|
|
@@ -383,12 +374,12 @@ describe('IndexLevel', () => {
|
|
|
383
374
|
lte: 'foobaz'
|
|
384
375
|
}
|
|
385
376
|
}];
|
|
386
|
-
const lteReply =
|
|
377
|
+
const lteReply = await testIndex.queryWithInMemoryPaging(tenant, lteFilter, { sortProperty: 'id' });
|
|
387
378
|
expect(lteReply.length).toBe(3);
|
|
388
379
|
expect(lteReply.map(({ messageCid }) => messageCid)).toEqual(expect.arrayContaining([id, id2, id3]));
|
|
389
|
-
})
|
|
380
|
+
});
|
|
390
381
|
describe('array values', () => {
|
|
391
|
-
it('query items with string array values', () =>
|
|
382
|
+
it('query items with string array values', async () => {
|
|
392
383
|
const items = [{
|
|
393
384
|
id: uuid(),
|
|
394
385
|
tag: ['item1', 'item']
|
|
@@ -403,18 +394,18 @@ describe('IndexLevel', () => {
|
|
|
403
394
|
tag: ['item4', 'item']
|
|
404
395
|
}];
|
|
405
396
|
for (const item of items) {
|
|
406
|
-
|
|
397
|
+
await testIndex.put(tenant, item.id, item);
|
|
407
398
|
}
|
|
408
399
|
const filterForItemTag = [{ tag: 'item' }];
|
|
409
|
-
const allResults =
|
|
400
|
+
const allResults = await testIndex.queryWithInMemoryPaging(tenant, filterForItemTag, { sortProperty: 'id' });
|
|
410
401
|
expect(allResults.length).toBe(4);
|
|
411
402
|
expect(allResults.map(item => item.messageCid)).toEqual(expect.arrayContaining(items.map(item => item.id)));
|
|
412
403
|
const filterForItem3 = [{ tag: 'item3' }];
|
|
413
|
-
const item3Results =
|
|
404
|
+
const item3Results = await testIndex.queryWithInMemoryPaging(tenant, filterForItem3, { sortProperty: 'id' });
|
|
414
405
|
expect(item3Results.length).toBe(1);
|
|
415
406
|
expect(item3Results.map(item => item.messageCid)).toEqual(expect.arrayContaining([items[2].id]));
|
|
416
|
-
})
|
|
417
|
-
it('query items with number array values', () =>
|
|
407
|
+
});
|
|
408
|
+
it('query items with number array values', async () => {
|
|
418
409
|
const items = [{
|
|
419
410
|
id: uuid(),
|
|
420
411
|
tag: [1]
|
|
@@ -429,36 +420,36 @@ describe('IndexLevel', () => {
|
|
|
429
420
|
tag: [1, 4]
|
|
430
421
|
}];
|
|
431
422
|
for (const item of items) {
|
|
432
|
-
|
|
423
|
+
await testIndex.put(tenant, item.id, item);
|
|
433
424
|
}
|
|
434
425
|
const filterForItemTag = [{ tag: 1 }];
|
|
435
|
-
const allResults =
|
|
426
|
+
const allResults = await testIndex.queryWithInMemoryPaging(tenant, filterForItemTag, { sortProperty: 'id' });
|
|
436
427
|
expect(allResults.length).toBe(4);
|
|
437
428
|
expect(allResults.map(item => item.messageCid)).toEqual(expect.arrayContaining(items.map(item => item.id)));
|
|
438
429
|
const filterForItem3 = [{ tag: 3 }];
|
|
439
|
-
const item3Results =
|
|
430
|
+
const item3Results = await testIndex.queryWithInMemoryPaging(tenant, filterForItem3, { sortProperty: 'id' });
|
|
440
431
|
expect(item3Results.length).toBe(1);
|
|
441
432
|
expect(item3Results.map(item => item.messageCid)).toEqual(expect.arrayContaining([items[2].id]));
|
|
442
433
|
const filterForRange = [{ tag: { gt: 1, lt: 4 } }];
|
|
443
|
-
const rangeItems =
|
|
434
|
+
const rangeItems = await testIndex.queryWithInMemoryPaging(tenant, filterForRange, { sortProperty: 'id' });
|
|
444
435
|
expect(rangeItems.length).toBe(2);
|
|
445
436
|
expect(rangeItems.map(item => item.messageCid)).toEqual(expect.arrayContaining([items[1].id, items[2].id]));
|
|
446
|
-
})
|
|
437
|
+
});
|
|
447
438
|
});
|
|
448
439
|
});
|
|
449
440
|
describe('query()', () => {
|
|
450
|
-
it('should not match values prefixed with the query', () =>
|
|
441
|
+
it('should not match values prefixed with the query', async () => {
|
|
451
442
|
const id = uuid();
|
|
452
443
|
const doc = {
|
|
453
444
|
id,
|
|
454
445
|
value: 'foobar'
|
|
455
446
|
};
|
|
456
|
-
|
|
447
|
+
await testIndex.put(tenant, id, doc);
|
|
457
448
|
const filters = [{ value: 'foo' }];
|
|
458
|
-
const entries =
|
|
449
|
+
const entries = await testIndex.query(tenant, filters, { sortProperty: 'id' });
|
|
459
450
|
expect(entries.length).toBe(0);
|
|
460
|
-
})
|
|
461
|
-
it('supports OR queries', () =>
|
|
451
|
+
});
|
|
452
|
+
it('supports OR queries', async () => {
|
|
462
453
|
const id1 = uuid();
|
|
463
454
|
const doc1 = {
|
|
464
455
|
id: id1,
|
|
@@ -474,51 +465,51 @@ describe('IndexLevel', () => {
|
|
|
474
465
|
id: id3,
|
|
475
466
|
'a': 'c'
|
|
476
467
|
};
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
468
|
+
await testIndex.put(tenant, id1, doc1);
|
|
469
|
+
await testIndex.put(tenant, id2, doc2);
|
|
470
|
+
await testIndex.put(tenant, id3, doc3);
|
|
480
471
|
const filters = [{
|
|
481
472
|
a: ['a', 'b']
|
|
482
473
|
}];
|
|
483
|
-
const entries =
|
|
474
|
+
const entries = await testIndex.query(tenant, filters, { sortProperty: 'id' });
|
|
484
475
|
expect(entries.length).toBe(2);
|
|
485
476
|
expect(entries.map(({ messageCid }) => messageCid)).toContain(id1);
|
|
486
477
|
expect(entries.map(({ messageCid }) => messageCid)).toContain(id2);
|
|
487
|
-
})
|
|
488
|
-
it('supports range queries', () =>
|
|
478
|
+
});
|
|
479
|
+
it('supports range queries', async () => {
|
|
489
480
|
for (let i = -5; i < 5; ++i) {
|
|
490
481
|
const id = uuid();
|
|
491
482
|
const doc = {
|
|
492
483
|
id,
|
|
493
484
|
dateCreated: Temporal.PlainDateTime.from({ year: 2023, month: 1, day: 15 + i }).toString({ smallestUnit: 'microseconds' })
|
|
494
485
|
};
|
|
495
|
-
|
|
486
|
+
await testIndex.put(tenant, id, doc);
|
|
496
487
|
}
|
|
497
488
|
const filters = [{
|
|
498
489
|
dateCreated: {
|
|
499
490
|
gte: Temporal.PlainDateTime.from({ year: 2023, month: 1, day: 15 }).toString({ smallestUnit: 'microseconds' })
|
|
500
491
|
}
|
|
501
492
|
}];
|
|
502
|
-
const entries =
|
|
493
|
+
const entries = await testIndex.query(tenant, filters, { sortProperty: 'id' });
|
|
503
494
|
expect(entries.length).toBe(5);
|
|
504
|
-
})
|
|
505
|
-
it('supports prefixed range queries', () =>
|
|
495
|
+
});
|
|
496
|
+
it('supports prefixed range queries', async () => {
|
|
506
497
|
const id = uuid();
|
|
507
498
|
const doc = {
|
|
508
499
|
id,
|
|
509
500
|
value: 'foobar'
|
|
510
501
|
};
|
|
511
|
-
|
|
502
|
+
await testIndex.put(tenant, id, doc);
|
|
512
503
|
const filters = [{
|
|
513
504
|
value: {
|
|
514
505
|
gte: 'foo'
|
|
515
506
|
}
|
|
516
507
|
}];
|
|
517
|
-
const entries =
|
|
508
|
+
const entries = await testIndex.query(tenant, filters, { sortProperty: 'id' });
|
|
518
509
|
expect(entries.length).toBe(1);
|
|
519
510
|
expect(entries.map(({ messageCid }) => messageCid)).toContain(id);
|
|
520
|
-
})
|
|
521
|
-
it('supports suffixed range queries', () =>
|
|
511
|
+
});
|
|
512
|
+
it('supports suffixed range queries', async () => {
|
|
522
513
|
const id1 = uuid();
|
|
523
514
|
const doc1 = {
|
|
524
515
|
id: id1,
|
|
@@ -529,18 +520,18 @@ describe('IndexLevel', () => {
|
|
|
529
520
|
id: id2,
|
|
530
521
|
foo: 'barbaz'
|
|
531
522
|
};
|
|
532
|
-
|
|
533
|
-
|
|
523
|
+
await testIndex.put(tenant, id1, doc1);
|
|
524
|
+
await testIndex.put(tenant, id2, doc2);
|
|
534
525
|
const filters = [{
|
|
535
526
|
foo: {
|
|
536
527
|
lte: 'bar'
|
|
537
528
|
}
|
|
538
529
|
}];
|
|
539
|
-
const entries =
|
|
530
|
+
const entries = await testIndex.query(tenant, filters, { sortProperty: 'id' });
|
|
540
531
|
expect(entries.length).toBe(1);
|
|
541
532
|
expect(entries.map(({ messageCid }) => messageCid)).toContain(id1);
|
|
542
|
-
})
|
|
543
|
-
it('treats strings differently', () =>
|
|
533
|
+
});
|
|
534
|
+
it('treats strings differently', async () => {
|
|
544
535
|
const id1 = uuid();
|
|
545
536
|
const doc1 = {
|
|
546
537
|
id: id1,
|
|
@@ -551,44 +542,43 @@ describe('IndexLevel', () => {
|
|
|
551
542
|
id: id2,
|
|
552
543
|
foo: 'true'
|
|
553
544
|
};
|
|
554
|
-
|
|
555
|
-
|
|
545
|
+
await testIndex.put(tenant, id1, doc1);
|
|
546
|
+
await testIndex.put(tenant, id2, doc2);
|
|
556
547
|
const filters = [{
|
|
557
548
|
foo: true
|
|
558
549
|
}];
|
|
559
|
-
const entries =
|
|
550
|
+
const entries = await testIndex.query(tenant, filters, { sortProperty: 'id' });
|
|
560
551
|
expect(entries.length).toBe(1);
|
|
561
552
|
expect(entries.map(({ messageCid }) => messageCid)).toContain(id1);
|
|
562
|
-
})
|
|
553
|
+
});
|
|
563
554
|
describe('numbers', () => {
|
|
564
555
|
const positiveDigits = Array(10).fill({}).map(_ => TestDataGenerator.randomInt(0, Number.MAX_SAFE_INTEGER)).sort((a, b) => a - b);
|
|
565
556
|
const negativeDigits = Array(10).fill({}).map(_ => TestDataGenerator.randomInt(0, Number.MAX_SAFE_INTEGER) * -1).sort((a, b) => a - b);
|
|
566
557
|
const testNumbers = Array.from(new Set([...negativeDigits, ...positiveDigits])); // unique numbers
|
|
567
|
-
it('should return records that match provided number equality filter', () =>
|
|
568
|
-
var _a;
|
|
558
|
+
it('should return records that match provided number equality filter', async () => {
|
|
569
559
|
const index = Math.floor(Math.random() * testNumbers.length);
|
|
570
560
|
for (const digit of testNumbers) {
|
|
571
|
-
|
|
561
|
+
await testIndex.put(tenant, digit.toString(), { digit });
|
|
572
562
|
}
|
|
573
563
|
const filters = [{
|
|
574
564
|
digit: testNumbers.at(index)
|
|
575
565
|
}];
|
|
576
|
-
const entries =
|
|
566
|
+
const entries = await testIndex.query(tenant, filters, { sortProperty: 'digit' });
|
|
577
567
|
expect(entries.length).toBe(1);
|
|
578
|
-
expect(
|
|
579
|
-
})
|
|
580
|
-
it('should not return records that do not match provided number equality filter', () =>
|
|
568
|
+
expect(entries.at(0)?.messageCid).toBe(testNumbers.at(index).toString());
|
|
569
|
+
});
|
|
570
|
+
it('should not return records that do not match provided number equality filter', async () => {
|
|
581
571
|
// remove the potential (but unlikely) negative test result
|
|
582
572
|
for (const digit of testNumbers.filter(n => n !== 1)) {
|
|
583
|
-
|
|
573
|
+
await testIndex.put(tenant, digit.toString(), { digit });
|
|
584
574
|
}
|
|
585
575
|
const filters = [{ digit: 1 }];
|
|
586
|
-
const entries =
|
|
576
|
+
const entries = await testIndex.query(tenant, filters, { sortProperty: 'digit' });
|
|
587
577
|
expect(entries.length).toBe(0);
|
|
588
|
-
})
|
|
589
|
-
it('supports range queries with positive numbers inclusive', () =>
|
|
578
|
+
});
|
|
579
|
+
it('supports range queries with positive numbers inclusive', async () => {
|
|
590
580
|
for (const digit of testNumbers) {
|
|
591
|
-
|
|
581
|
+
await testIndex.put(tenant, digit.toString(), { digit });
|
|
592
582
|
}
|
|
593
583
|
const upperBound = positiveDigits.at(positiveDigits.length - 3);
|
|
594
584
|
const lowerBound = positiveDigits.at(2);
|
|
@@ -598,13 +588,13 @@ describe('IndexLevel', () => {
|
|
|
598
588
|
lte: upperBound
|
|
599
589
|
}
|
|
600
590
|
}];
|
|
601
|
-
const entries =
|
|
591
|
+
const entries = await testIndex.query(tenant, filters, { sortProperty: 'digit' });
|
|
602
592
|
const testResults = testNumbers.filter(n => n >= lowerBound && n <= upperBound).map(n => n.toString());
|
|
603
593
|
expect(entries.map(({ messageCid }) => messageCid)).toEqual(testResults);
|
|
604
|
-
})
|
|
605
|
-
it('supports range queries with negative numbers inclusive', () =>
|
|
594
|
+
});
|
|
595
|
+
it('supports range queries with negative numbers inclusive', async () => {
|
|
606
596
|
for (const digit of testNumbers) {
|
|
607
|
-
|
|
597
|
+
await testIndex.put(tenant, digit.toString(), { digit });
|
|
608
598
|
}
|
|
609
599
|
const upperBound = negativeDigits.at(negativeDigits.length - 2);
|
|
610
600
|
const lowerBound = negativeDigits.at(2);
|
|
@@ -614,13 +604,13 @@ describe('IndexLevel', () => {
|
|
|
614
604
|
lte: upperBound
|
|
615
605
|
}
|
|
616
606
|
}];
|
|
617
|
-
const entries =
|
|
607
|
+
const entries = await testIndex.query(tenant, filters, { sortProperty: 'digit' });
|
|
618
608
|
const testResults = testNumbers.filter(n => n >= lowerBound && n <= upperBound).map(n => n.toString());
|
|
619
609
|
expect(entries.map(({ messageCid }) => messageCid)).toEqual(testResults);
|
|
620
|
-
})
|
|
621
|
-
it('should return numbers gt a negative digit', () =>
|
|
610
|
+
});
|
|
611
|
+
it('should return numbers gt a negative digit', async () => {
|
|
622
612
|
for (const digit of testNumbers) {
|
|
623
|
-
|
|
613
|
+
await testIndex.put(tenant, digit.toString(), { digit });
|
|
624
614
|
}
|
|
625
615
|
const lowerBound = negativeDigits.at(4);
|
|
626
616
|
const filters = [{
|
|
@@ -628,13 +618,13 @@ describe('IndexLevel', () => {
|
|
|
628
618
|
gt: lowerBound,
|
|
629
619
|
}
|
|
630
620
|
}];
|
|
631
|
-
const entries =
|
|
621
|
+
const entries = await testIndex.query(tenant, filters, { sortProperty: 'digit' });
|
|
632
622
|
const testResults = testNumbers.filter(n => n > lowerBound).map(n => n.toString());
|
|
633
623
|
expect(entries.map(({ messageCid }) => messageCid)).toEqual(testResults);
|
|
634
|
-
})
|
|
635
|
-
it('should return numbers gt a digit', () =>
|
|
624
|
+
});
|
|
625
|
+
it('should return numbers gt a digit', async () => {
|
|
636
626
|
for (const digit of testNumbers) {
|
|
637
|
-
|
|
627
|
+
await testIndex.put(tenant, digit.toString(), { digit });
|
|
638
628
|
}
|
|
639
629
|
const lowerBound = positiveDigits.at(4);
|
|
640
630
|
const filters = [{
|
|
@@ -642,13 +632,13 @@ describe('IndexLevel', () => {
|
|
|
642
632
|
gt: lowerBound,
|
|
643
633
|
}
|
|
644
634
|
}];
|
|
645
|
-
const entries =
|
|
635
|
+
const entries = await testIndex.query(tenant, filters, { sortProperty: 'digit' });
|
|
646
636
|
const testResults = testNumbers.filter(n => n > lowerBound).map(n => n.toString());
|
|
647
637
|
expect(entries.map(({ messageCid }) => messageCid)).toEqual(testResults);
|
|
648
|
-
})
|
|
649
|
-
it('should return numbers lt a negative digit', () =>
|
|
638
|
+
});
|
|
639
|
+
it('should return numbers lt a negative digit', async () => {
|
|
650
640
|
for (const digit of testNumbers) {
|
|
651
|
-
|
|
641
|
+
await testIndex.put(tenant, digit.toString(), { digit });
|
|
652
642
|
}
|
|
653
643
|
const upperBound = negativeDigits.at(4);
|
|
654
644
|
const filters = [{
|
|
@@ -656,13 +646,13 @@ describe('IndexLevel', () => {
|
|
|
656
646
|
lt: upperBound,
|
|
657
647
|
}
|
|
658
648
|
}];
|
|
659
|
-
const entries =
|
|
649
|
+
const entries = await testIndex.query(tenant, filters, { sortProperty: 'digit' });
|
|
660
650
|
const testResults = testNumbers.filter(n => n < upperBound).map(n => n.toString());
|
|
661
651
|
expect(entries.map(({ messageCid }) => messageCid)).toEqual(testResults);
|
|
662
|
-
})
|
|
663
|
-
it('should return numbers lt a digit', () =>
|
|
652
|
+
});
|
|
653
|
+
it('should return numbers lt a digit', async () => {
|
|
664
654
|
for (const digit of testNumbers) {
|
|
665
|
-
|
|
655
|
+
await testIndex.put(tenant, digit.toString(), { digit });
|
|
666
656
|
}
|
|
667
657
|
const upperBound = positiveDigits.at(4);
|
|
668
658
|
const filters = [{
|
|
@@ -670,117 +660,117 @@ describe('IndexLevel', () => {
|
|
|
670
660
|
lt: upperBound,
|
|
671
661
|
}
|
|
672
662
|
}];
|
|
673
|
-
const entries =
|
|
663
|
+
const entries = await testIndex.query(tenant, filters, { sortProperty: 'digit' });
|
|
674
664
|
const testResults = testNumbers.filter(n => n < upperBound).map(n => n.toString());
|
|
675
665
|
expect(entries.map(({ messageCid }) => messageCid)).toEqual(testResults);
|
|
676
|
-
})
|
|
666
|
+
});
|
|
677
667
|
});
|
|
678
668
|
describe('booleans', () => {
|
|
679
|
-
it('should return records that match provided boolean equality filter', () =>
|
|
669
|
+
it('should return records that match provided boolean equality filter', async () => {
|
|
680
670
|
const itemTrueId = uuid();
|
|
681
671
|
const boolTrueItem = {
|
|
682
672
|
id: itemTrueId,
|
|
683
673
|
schema: 'schema',
|
|
684
674
|
published: true,
|
|
685
675
|
};
|
|
686
|
-
|
|
676
|
+
await testIndex.put(tenant, itemTrueId, boolTrueItem);
|
|
687
677
|
const itemFalseId = uuid();
|
|
688
678
|
const boolFalseItem = {
|
|
689
679
|
id: itemFalseId,
|
|
690
680
|
schema: 'schema',
|
|
691
681
|
published: false,
|
|
692
682
|
};
|
|
693
|
-
|
|
683
|
+
await testIndex.put(tenant, itemFalseId, boolFalseItem);
|
|
694
684
|
const bothFilter = [{ schema: 'schema' }];
|
|
695
685
|
// control
|
|
696
|
-
const entries =
|
|
686
|
+
const entries = await testIndex.query(tenant, bothFilter, { sortProperty: 'id' });
|
|
697
687
|
expect(entries.length).toBe(2);
|
|
698
688
|
expect(entries.map(({ messageCid }) => messageCid)).toEqual(expect.arrayContaining([itemTrueId, itemFalseId]));
|
|
699
689
|
const trueFilter = [{ published: true, schema: 'schema' }];
|
|
700
690
|
// equality true
|
|
701
|
-
const respTrue =
|
|
691
|
+
const respTrue = await testIndex.query(tenant, trueFilter, { sortProperty: 'id' });
|
|
702
692
|
expect(respTrue.length).toBe(1);
|
|
703
693
|
expect(respTrue.map(({ messageCid }) => messageCid)).toEqual(expect.arrayContaining([itemTrueId]));
|
|
704
694
|
const falseFilter = [{ published: false, schema: 'schema' }];
|
|
705
695
|
// equality false
|
|
706
|
-
const respFalse =
|
|
696
|
+
const respFalse = await testIndex.query(tenant, falseFilter, { sortProperty: 'id' });
|
|
707
697
|
expect(respFalse.length).toBe(1);
|
|
708
698
|
expect(respFalse.map(({ messageCid }) => messageCid)).toEqual(expect.arrayContaining([itemFalseId]));
|
|
709
|
-
})
|
|
699
|
+
});
|
|
710
700
|
});
|
|
711
701
|
describe('sort, limit and cursor', () => {
|
|
712
|
-
it('only returns the number of results specified by the limit property', () =>
|
|
702
|
+
it('only returns the number of results specified by the limit property', async () => {
|
|
713
703
|
const testVals = ['b', 'a', 'd', 'c'];
|
|
714
704
|
for (const val of testVals) {
|
|
715
|
-
|
|
705
|
+
await testIndex.put(tenant, val, { val, schema: 'schema' });
|
|
716
706
|
}
|
|
717
707
|
const filters = [{ schema: 'schema' }];
|
|
718
708
|
// limit results without cursor
|
|
719
|
-
let ascResults =
|
|
709
|
+
let ascResults = await testIndex.query(tenant, filters, { sortProperty: 'val', limit: 2 });
|
|
720
710
|
expect(ascResults.length).toBe(2);
|
|
721
711
|
expect(ascResults.map(({ messageCid }) => messageCid)).toEqual(['a', 'b']);
|
|
722
712
|
// limit results with a cursor
|
|
723
|
-
ascResults =
|
|
713
|
+
ascResults = await testIndex.query(tenant, filters, { sortProperty: 'val', limit: 2, cursor: IndexLevel.createCursorFromLastArrayItem(ascResults, 'val') });
|
|
724
714
|
expect(ascResults.length).toBe(2);
|
|
725
715
|
expect(ascResults.map(({ messageCid }) => messageCid)).toEqual(['c', 'd']);
|
|
726
|
-
})
|
|
727
|
-
it('can sort by any indexed property', () =>
|
|
716
|
+
});
|
|
717
|
+
it('can sort by any indexed property', async () => {
|
|
728
718
|
const testVals = ['b', 'd', 'c', 'a'];
|
|
729
719
|
for (const val of testVals) {
|
|
730
|
-
|
|
720
|
+
await testIndex.put(tenant, val, { val, schema: 'schema', index: testVals.indexOf(val) });
|
|
731
721
|
}
|
|
732
722
|
const filters = [{ schema: 'schema' }];
|
|
733
723
|
// sort by value ascending
|
|
734
|
-
const ascResults =
|
|
724
|
+
const ascResults = await testIndex.query(tenant, filters, { sortProperty: 'val' });
|
|
735
725
|
expect(ascResults.length).toBe(testVals.length);
|
|
736
726
|
expect(ascResults.map(({ messageCid }) => messageCid)).toEqual(['a', 'b', 'c', 'd']);
|
|
737
727
|
// sort by index ascending
|
|
738
|
-
const ascIndexResults =
|
|
728
|
+
const ascIndexResults = await testIndex.query(tenant, filters, { sortProperty: 'index' });
|
|
739
729
|
expect(ascIndexResults.length).toBe(testVals.length);
|
|
740
730
|
expect(ascIndexResults.map(({ messageCid }) => messageCid)).toEqual(testVals);
|
|
741
731
|
// sort by value descending
|
|
742
|
-
const descResults =
|
|
732
|
+
const descResults = await testIndex.query(tenant, filters, { sortProperty: 'val', sortDirection: SortDirection.Descending });
|
|
743
733
|
expect(descResults.length).toBe(testVals.length);
|
|
744
734
|
expect(descResults.map(({ messageCid }) => messageCid)).toEqual(['d', 'c', 'b', 'a']);
|
|
745
735
|
// sort by index descending
|
|
746
|
-
const descIndexResults =
|
|
736
|
+
const descIndexResults = await testIndex.query(tenant, filters, { sortProperty: 'index', sortDirection: SortDirection.Descending });
|
|
747
737
|
expect(descIndexResults.length).toBe(testVals.length);
|
|
748
738
|
expect(descIndexResults.map(({ messageCid }) => messageCid)).toEqual([...testVals].reverse());
|
|
749
|
-
})
|
|
750
|
-
it('sorts lexicographic', () =>
|
|
739
|
+
});
|
|
740
|
+
it('sorts lexicographic', async () => {
|
|
751
741
|
const testVals = ['b', 'a', 'd', 'c'];
|
|
752
742
|
for (const val of testVals) {
|
|
753
|
-
|
|
743
|
+
await testIndex.put(tenant, val, { val, schema: 'schema' });
|
|
754
744
|
}
|
|
755
745
|
const filters = [{ schema: 'schema' }];
|
|
756
746
|
// sort ascending
|
|
757
|
-
const ascResults =
|
|
747
|
+
const ascResults = await testIndex.query(tenant, filters, { sortProperty: 'val' });
|
|
758
748
|
expect(ascResults.length).toBe(4);
|
|
759
749
|
expect(ascResults.map(({ messageCid }) => messageCid)).toEqual(['a', 'b', 'c', 'd']);
|
|
760
750
|
// sort descending
|
|
761
|
-
const descResults =
|
|
751
|
+
const descResults = await testIndex.query(tenant, filters, { sortProperty: 'val', sortDirection: SortDirection.Descending });
|
|
762
752
|
expect(descResults.length).toBe(4);
|
|
763
753
|
expect(descResults.map(({ messageCid }) => messageCid)).toEqual(['d', 'c', 'b', 'a']);
|
|
764
|
-
})
|
|
765
|
-
it('sorts numeric with and without a cursor', () =>
|
|
754
|
+
});
|
|
755
|
+
it('sorts numeric with and without a cursor', async () => {
|
|
766
756
|
const testVals = [-2, -1, 0, 1, 2, 3, 4];
|
|
767
757
|
for (const val of testVals) {
|
|
768
|
-
|
|
758
|
+
await testIndex.put(tenant, val.toString(), { val, schema: 'schema' });
|
|
769
759
|
}
|
|
770
760
|
const filters = [{ schema: 'schema' }];
|
|
771
761
|
// sort ascending
|
|
772
|
-
const ascResults =
|
|
762
|
+
const ascResults = await testIndex.query(tenant, filters, { sortProperty: 'val' });
|
|
773
763
|
expect(ascResults.length).toBe(testVals.length);
|
|
774
764
|
expect(ascResults.map(({ messageCid }) => messageCid)).toEqual(['-2', '-1', '0', '1', '2', '3', '4']);
|
|
775
765
|
// sort descending
|
|
776
|
-
const descResults =
|
|
766
|
+
const descResults = await testIndex.query(tenant, filters, { sortProperty: 'val', sortDirection: SortDirection.Descending });
|
|
777
767
|
expect(descResults.length).toEqual(testVals.length);
|
|
778
768
|
expect(descResults.map(({ messageCid }) => messageCid)).toEqual(['4', '3', '2', '1', '0', '-1', '-2']);
|
|
779
|
-
})
|
|
780
|
-
it('sorts range queries with or without a cursor', () =>
|
|
769
|
+
});
|
|
770
|
+
it('sorts range queries with or without a cursor', async () => {
|
|
781
771
|
const testItems = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
|
|
782
772
|
for (const item of testItems) {
|
|
783
|
-
|
|
773
|
+
await testIndex.put(tenant, item, { letter: item });
|
|
784
774
|
}
|
|
785
775
|
// test both upper and lower bounds
|
|
786
776
|
const lowerBound = 'b';
|
|
@@ -792,16 +782,16 @@ describe('IndexLevel', () => {
|
|
|
792
782
|
},
|
|
793
783
|
}];
|
|
794
784
|
// ascending without a cursor
|
|
795
|
-
let response =
|
|
785
|
+
let response = await testIndex.query(tenant, bothBoundsFilters, { sortProperty: 'letter', limit: 4 });
|
|
796
786
|
expect(response.map(({ messageCid }) => messageCid)).toEqual(['b', 'c', 'd', 'e']);
|
|
797
787
|
// ascending with a cursor
|
|
798
|
-
response =
|
|
788
|
+
response = await testIndex.query(tenant, bothBoundsFilters, { sortProperty: 'letter', cursor: IndexLevel.createCursorFromLastArrayItem(response, 'letter') });
|
|
799
789
|
expect(response.map(({ messageCid }) => messageCid)).toEqual(['f', 'g']); // should only return greater than e
|
|
800
790
|
// descending without a cursor
|
|
801
|
-
response =
|
|
791
|
+
response = await testIndex.query(tenant, bothBoundsFilters, { sortProperty: 'letter', sortDirection: SortDirection.Descending, limit: 4 });
|
|
802
792
|
expect(response.map(({ messageCid }) => messageCid)).toEqual(['g', 'f', 'e', 'd']);
|
|
803
793
|
// descending with a cursor
|
|
804
|
-
response =
|
|
794
|
+
response = await testIndex.query(tenant, bothBoundsFilters, { sortProperty: 'letter', sortDirection: SortDirection.Descending, cursor: IndexLevel.createCursorFromLastArrayItem(response, 'letter') });
|
|
805
795
|
expect(response.map(({ messageCid }) => messageCid)).toEqual(['c', 'b']); // should only return less than d
|
|
806
796
|
// test only upper bounds
|
|
807
797
|
const upperBoundsFilters = [{
|
|
@@ -810,16 +800,16 @@ describe('IndexLevel', () => {
|
|
|
810
800
|
},
|
|
811
801
|
}];
|
|
812
802
|
// ascending without a cursor
|
|
813
|
-
response =
|
|
803
|
+
response = await testIndex.query(tenant, upperBoundsFilters, { sortProperty: 'letter', limit: 4 });
|
|
814
804
|
expect(response.map(({ messageCid }) => messageCid)).toEqual(['a', 'b', 'c', 'd']);
|
|
815
805
|
// ascending with a cursor
|
|
816
|
-
response =
|
|
806
|
+
response = await testIndex.query(tenant, upperBoundsFilters, { sortProperty: 'letter', cursor: IndexLevel.createCursorFromLastArrayItem(response, 'letter') });
|
|
817
807
|
expect(response.map(({ messageCid }) => messageCid)).toEqual(['e', 'f', 'g']); // should only return items greater than d
|
|
818
808
|
// descending without a cursor
|
|
819
|
-
response =
|
|
809
|
+
response = await testIndex.query(tenant, upperBoundsFilters, { sortProperty: 'letter', sortDirection: SortDirection.Descending, limit: 4 });
|
|
820
810
|
expect(response.map(({ messageCid }) => messageCid)).toEqual(['g', 'f', 'e', 'd']);
|
|
821
811
|
// descending with a cursor
|
|
822
|
-
response =
|
|
812
|
+
response = await testIndex.query(tenant, upperBoundsFilters, { sortProperty: 'letter', sortDirection: SortDirection.Descending, cursor: IndexLevel.createCursorFromLastArrayItem(response, 'letter') });
|
|
823
813
|
expect(response.map(({ messageCid }) => messageCid)).toEqual(['c', 'b', 'a']); // should only return items less than c
|
|
824
814
|
// test only lower bounds
|
|
825
815
|
const lowerBoundsFilters = [{
|
|
@@ -828,22 +818,22 @@ describe('IndexLevel', () => {
|
|
|
828
818
|
},
|
|
829
819
|
}];
|
|
830
820
|
// ascending without a cursor
|
|
831
|
-
response =
|
|
821
|
+
response = await testIndex.query(tenant, lowerBoundsFilters, { sortProperty: 'letter', limit: 4 });
|
|
832
822
|
expect(response.map(({ messageCid }) => messageCid)).toEqual(['b', 'c', 'd', 'e']);
|
|
833
823
|
// ascending with a cursor
|
|
834
|
-
response =
|
|
824
|
+
response = await testIndex.query(tenant, lowerBoundsFilters, { sortProperty: 'letter', cursor: IndexLevel.createCursorFromLastArrayItem(response, 'letter') });
|
|
835
825
|
expect(response.map(({ messageCid }) => messageCid)).toEqual(['f', 'g', 'h']); // should only return items greater than e
|
|
836
826
|
// descending without a cursor
|
|
837
|
-
response =
|
|
827
|
+
response = await testIndex.query(tenant, lowerBoundsFilters, { sortProperty: 'letter', sortDirection: SortDirection.Descending, limit: 4 });
|
|
838
828
|
expect(response.map(({ messageCid }) => messageCid)).toEqual(['h', 'g', 'f', 'e']);
|
|
839
829
|
// descending with a cursor
|
|
840
|
-
response =
|
|
830
|
+
response = await testIndex.query(tenant, lowerBoundsFilters, { sortProperty: 'letter', sortDirection: SortDirection.Descending, cursor: IndexLevel.createCursorFromLastArrayItem(response, 'letter') });
|
|
841
831
|
expect(response.map(({ messageCid }) => messageCid)).toEqual(['d', 'c', 'b']); // should only return items less than e
|
|
842
|
-
})
|
|
843
|
-
it('sorts range queries negative integers with or without a cursor', () =>
|
|
832
|
+
});
|
|
833
|
+
it('sorts range queries negative integers with or without a cursor', async () => {
|
|
844
834
|
const testNumbers = [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5];
|
|
845
835
|
for (const digit of testNumbers) {
|
|
846
|
-
|
|
836
|
+
await testIndex.put(tenant, digit.toString(), { digit });
|
|
847
837
|
}
|
|
848
838
|
const upperBound = 3;
|
|
849
839
|
const lowerBound = -2;
|
|
@@ -853,14 +843,14 @@ describe('IndexLevel', () => {
|
|
|
853
843
|
lte: upperBound
|
|
854
844
|
}
|
|
855
845
|
}];
|
|
856
|
-
let results =
|
|
846
|
+
let results = await testIndex.query(tenant, filters, { sortProperty: 'digit', limit: 4 });
|
|
857
847
|
expect(results.map(({ messageCid }) => messageCid)).toEqual(['-2', '-1', '0', '1']);
|
|
858
848
|
const cursor = IndexLevel.createCursorFromLastArrayItem(results, 'digit');
|
|
859
|
-
expect(typeof
|
|
860
|
-
results =
|
|
849
|
+
expect(typeof cursor?.value).toBe('number'); // the cursor value is a number, as it was indexed
|
|
850
|
+
results = await testIndex.query(tenant, filters, { sortProperty: 'digit', cursor });
|
|
861
851
|
expect(results.map(({ messageCid }) => messageCid)).toEqual(['2', '3']);
|
|
862
|
-
})
|
|
863
|
-
it('sorts range queries with remaining results in lte after cursor', () =>
|
|
852
|
+
});
|
|
853
|
+
it('sorts range queries with remaining results in lte after cursor', async () => {
|
|
864
854
|
// create an array with unique IDs but multiple items representing the same digit.
|
|
865
855
|
const testItems = [{
|
|
866
856
|
id: 'a',
|
|
@@ -888,13 +878,13 @@ describe('IndexLevel', () => {
|
|
|
888
878
|
digit: 5,
|
|
889
879
|
}];
|
|
890
880
|
for (const item of testItems) {
|
|
891
|
-
|
|
881
|
+
await testIndex.put(tenant, item.id, item);
|
|
892
882
|
}
|
|
893
883
|
const lowerBound = 2;
|
|
894
884
|
const upperBound = 4;
|
|
895
885
|
// with both lower and upper bounds
|
|
896
886
|
// first issue with a limit
|
|
897
|
-
let response =
|
|
887
|
+
let response = await testIndex.query(tenant, [{
|
|
898
888
|
digit: {
|
|
899
889
|
gte: lowerBound,
|
|
900
890
|
lte: upperBound
|
|
@@ -902,7 +892,7 @@ describe('IndexLevel', () => {
|
|
|
902
892
|
}], { sortProperty: 'id', limit: 3 });
|
|
903
893
|
expect(response.map(({ messageCid }) => messageCid)).toEqual(['b', 'c', 'd']);
|
|
904
894
|
// this cursor should ony return results from the 'lte' part of the filter
|
|
905
|
-
response =
|
|
895
|
+
response = await testIndex.query(tenant, [{
|
|
906
896
|
digit: {
|
|
907
897
|
gte: lowerBound,
|
|
908
898
|
lte: upperBound
|
|
@@ -910,7 +900,7 @@ describe('IndexLevel', () => {
|
|
|
910
900
|
}], { sortProperty: 'id', cursor: IndexLevel.createCursorFromLastArrayItem(response, 'id') });
|
|
911
901
|
expect(response.map(({ messageCid }) => messageCid)).toEqual(['e', 'f', 'g']);
|
|
912
902
|
// issue a range with no lower bounds but a limit
|
|
913
|
-
response =
|
|
903
|
+
response = await testIndex.query(tenant, [{
|
|
914
904
|
digit: {
|
|
915
905
|
lte: upperBound
|
|
916
906
|
},
|
|
@@ -919,33 +909,33 @@ describe('IndexLevel', () => {
|
|
|
919
909
|
// with no lower bounds
|
|
920
910
|
// ascending with a cursor
|
|
921
911
|
// this cursor should ony return results from the 'lte' part of the filter
|
|
922
|
-
response =
|
|
912
|
+
response = await testIndex.query(tenant, [{
|
|
923
913
|
digit: {
|
|
924
914
|
lte: upperBound
|
|
925
915
|
},
|
|
926
916
|
}], { sortProperty: 'id', cursor: IndexLevel.createCursorFromLastArrayItem(response, 'id') });
|
|
927
917
|
expect(response.map(({ messageCid }) => messageCid)).toEqual(['e', 'f', 'g']); // should only return three matching items
|
|
928
|
-
})
|
|
929
|
-
it('sorts OR queries with or without a cursor', () =>
|
|
918
|
+
});
|
|
919
|
+
it('sorts OR queries with or without a cursor', async () => {
|
|
930
920
|
const testValsSchema1 = ['a1', 'b1', 'c1', 'd1'];
|
|
931
921
|
for (const val of testValsSchema1) {
|
|
932
|
-
|
|
922
|
+
await testIndex.put(tenant, val, { val, schema: 'schema1' });
|
|
933
923
|
}
|
|
934
924
|
const testValsSchema2 = ['a2', 'b2', 'c2', 'd2'];
|
|
935
925
|
for (const val of testValsSchema2) {
|
|
936
|
-
|
|
926
|
+
await testIndex.put(tenant, val, { val, schema: 'schema2' });
|
|
937
927
|
}
|
|
938
928
|
const filters = [{
|
|
939
929
|
schema: ['schema1', 'schema2']
|
|
940
930
|
}];
|
|
941
931
|
// sort ascending without cursor
|
|
942
|
-
let results =
|
|
932
|
+
let results = await testIndex.query(tenant, filters, { sortProperty: 'val', limit: 4 });
|
|
943
933
|
expect(results.map(({ messageCid }) => messageCid)).toEqual(['a1', 'a2', 'b1', 'b2']);
|
|
944
934
|
// sort ascending from b2 onwards
|
|
945
|
-
results =
|
|
935
|
+
results = await testIndex.query(tenant, filters, { sortProperty: 'val', cursor: IndexLevel.createCursorFromLastArrayItem(results, 'val') });
|
|
946
936
|
expect(results.map(({ messageCid }) => messageCid)).toEqual(['c1', 'c2', 'd1', 'd2']);
|
|
947
|
-
})
|
|
948
|
-
it('supports multiple filtered queries', () =>
|
|
937
|
+
});
|
|
938
|
+
it('supports multiple filtered queries', async () => {
|
|
949
939
|
const items = [];
|
|
950
940
|
const lowerBounds = -2;
|
|
951
941
|
const upperBounds = 3;
|
|
@@ -961,7 +951,7 @@ describe('IndexLevel', () => {
|
|
|
961
951
|
TestDataGenerator.randomInt(1, 9);
|
|
962
952
|
const property = i % 5 === 0 ? true : false;
|
|
963
953
|
const item = { val: IndexLevel.encodeNumberValue(i), digit, property };
|
|
964
|
-
|
|
954
|
+
await testIndex.put(tenant, item.val, item);
|
|
965
955
|
items.push(item);
|
|
966
956
|
}
|
|
967
957
|
// create the expected results;
|
|
@@ -974,36 +964,36 @@ describe('IndexLevel', () => {
|
|
|
974
964
|
{ property: true }
|
|
975
965
|
];
|
|
976
966
|
// query in ascending order.
|
|
977
|
-
const results =
|
|
967
|
+
const results = await testIndex.query(tenant, filters, { sortProperty: 'val', limit: 10 });
|
|
978
968
|
expect(results.length).toBeLessThanOrEqual(10);
|
|
979
969
|
expect(results.map(({ messageCid }) => messageCid)).toEqual([...compareResults].slice(0, 10));
|
|
980
970
|
// query in ascending order with cursor.
|
|
981
|
-
const resultsWithCursor =
|
|
971
|
+
const resultsWithCursor = await testIndex.query(tenant, filters, { sortProperty: 'val', cursor: IndexLevel.createCursorFromLastArrayItem(results, 'val') });
|
|
982
972
|
expect(resultsWithCursor.map(({ messageCid }) => messageCid)).toEqual([...compareResults].slice(10));
|
|
983
|
-
const descResults =
|
|
973
|
+
const descResults = await testIndex.query(tenant, filters, { sortProperty: 'val', sortDirection: SortDirection.Descending, limit: 10 });
|
|
984
974
|
expect(descResults.length).toBeLessThanOrEqual(10);
|
|
985
975
|
expect(descResults.map(({ messageCid }) => messageCid)).toEqual([...compareResults].reverse().slice(0, 10));
|
|
986
|
-
const descResultsAfterCursor =
|
|
976
|
+
const descResultsAfterCursor = await testIndex.query(tenant, filters, { sortProperty: 'val', sortDirection: SortDirection.Descending, cursor: IndexLevel.createCursorFromLastArrayItem(descResults, 'val') });
|
|
987
977
|
expect(descResultsAfterCursor.map(({ messageCid }) => messageCid)).toEqual([...compareResults].reverse().slice(10));
|
|
988
|
-
})
|
|
978
|
+
});
|
|
989
979
|
});
|
|
990
980
|
});
|
|
991
981
|
});
|
|
992
982
|
describe('delete', () => {
|
|
993
|
-
beforeAll(() =>
|
|
983
|
+
beforeAll(async () => {
|
|
994
984
|
testIndex = new IndexLevel({
|
|
995
985
|
createLevelDatabase,
|
|
996
986
|
location: 'TEST-INDEX',
|
|
997
987
|
});
|
|
998
|
-
|
|
999
|
-
})
|
|
1000
|
-
beforeEach(() =>
|
|
1001
|
-
|
|
1002
|
-
})
|
|
1003
|
-
afterAll(() =>
|
|
1004
|
-
|
|
1005
|
-
})
|
|
1006
|
-
it('purges indexes', () =>
|
|
988
|
+
await testIndex.open();
|
|
989
|
+
});
|
|
990
|
+
beforeEach(async () => {
|
|
991
|
+
await testIndex.clear();
|
|
992
|
+
});
|
|
993
|
+
afterAll(async () => {
|
|
994
|
+
await testIndex.close();
|
|
995
|
+
});
|
|
996
|
+
it('purges indexes', async () => {
|
|
1007
997
|
const id1 = uuid();
|
|
1008
998
|
const doc1 = {
|
|
1009
999
|
id: id1,
|
|
@@ -1016,19 +1006,19 @@ describe('IndexLevel', () => {
|
|
|
1016
1006
|
'a': 'b',
|
|
1017
1007
|
'c': ['d', 'e']
|
|
1018
1008
|
};
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
let result =
|
|
1009
|
+
await testIndex.put(tenant, id1, doc1);
|
|
1010
|
+
await testIndex.put(tenant, id2, doc2);
|
|
1011
|
+
let result = await testIndex.query(tenant, [{ 'a': 'b', 'c': 'e' }], { sortProperty: 'id' });
|
|
1022
1012
|
expect(result.length).toBe(2);
|
|
1023
1013
|
expect(result.map(({ messageCid }) => messageCid)).toContain(id1);
|
|
1024
|
-
|
|
1025
|
-
result =
|
|
1014
|
+
await testIndex.delete(tenant, id1);
|
|
1015
|
+
result = await testIndex.query(tenant, [{ 'a': 'b', 'c': 'e' }], { sortProperty: 'id' });
|
|
1026
1016
|
expect(result.length).toBe(1);
|
|
1027
|
-
|
|
1028
|
-
const allKeys =
|
|
1017
|
+
await testIndex.delete(tenant, id2);
|
|
1018
|
+
const allKeys = await ArrayUtility.fromAsyncGenerator(testIndex.db.keys());
|
|
1029
1019
|
expect(allKeys.length).toBe(0);
|
|
1030
|
-
})
|
|
1031
|
-
it('should not delete anything if aborted beforehand', () =>
|
|
1020
|
+
});
|
|
1021
|
+
it('should not delete anything if aborted beforehand', async () => {
|
|
1032
1022
|
const controller = new AbortController();
|
|
1033
1023
|
controller.abort('reason');
|
|
1034
1024
|
const id = uuid();
|
|
@@ -1036,18 +1026,18 @@ describe('IndexLevel', () => {
|
|
|
1036
1026
|
id: id,
|
|
1037
1027
|
foo: 'bar'
|
|
1038
1028
|
};
|
|
1039
|
-
|
|
1029
|
+
await testIndex.put(tenant, id, doc);
|
|
1040
1030
|
try {
|
|
1041
|
-
|
|
1031
|
+
await testIndex.delete(tenant, id, { signal: controller.signal });
|
|
1042
1032
|
}
|
|
1043
1033
|
catch (e) {
|
|
1044
1034
|
expect(e).toBe('reason');
|
|
1045
1035
|
}
|
|
1046
|
-
const result =
|
|
1036
|
+
const result = await testIndex.query(tenant, [{ foo: 'bar' }], { sortProperty: 'id' });
|
|
1047
1037
|
expect(result.length).toBe(1);
|
|
1048
1038
|
expect(result.map(({ messageCid }) => messageCid)).toContain(id);
|
|
1049
|
-
})
|
|
1050
|
-
it('does nothing when attempting to purge key that does not exist', () =>
|
|
1039
|
+
});
|
|
1040
|
+
it('does nothing when attempting to purge key that does not exist', async () => {
|
|
1051
1041
|
const controller = new AbortController();
|
|
1052
1042
|
controller.abort('reason');
|
|
1053
1043
|
const id = uuid();
|
|
@@ -1055,16 +1045,16 @@ describe('IndexLevel', () => {
|
|
|
1055
1045
|
id: id,
|
|
1056
1046
|
foo: 'bar'
|
|
1057
1047
|
};
|
|
1058
|
-
|
|
1048
|
+
await testIndex.put(tenant, id, doc);
|
|
1059
1049
|
// attempt purge an invalid id
|
|
1060
|
-
|
|
1061
|
-
const result =
|
|
1050
|
+
await testIndex.delete(tenant, 'invalidCid');
|
|
1051
|
+
const result = await testIndex.query(tenant, [{ foo: 'bar' }], { sortProperty: 'id' });
|
|
1062
1052
|
expect(result.length).toBe(1);
|
|
1063
1053
|
expect(result.map(({ messageCid }) => messageCid)).toContain(id);
|
|
1064
|
-
})
|
|
1054
|
+
});
|
|
1065
1055
|
});
|
|
1066
1056
|
describe('createCursorFromItem', () => {
|
|
1067
|
-
it('throws if cursor value is a boolean or an array', () =>
|
|
1057
|
+
it('throws if cursor value is a boolean or an array', async () => {
|
|
1068
1058
|
// we can only sort by strings or numbers, so arrays or booleans should throw.
|
|
1069
1059
|
const item = {
|
|
1070
1060
|
messageCid: 'message-cid',
|
|
@@ -1075,8 +1065,8 @@ describe('IndexLevel', () => {
|
|
|
1075
1065
|
};
|
|
1076
1066
|
expect(() => IndexLevel.createCursorFromItem(item, 'sortPropertyBool')).toThrow(DwnErrorCode.IndexInvalidCursorValueType);
|
|
1077
1067
|
expect(() => IndexLevel.createCursorFromItem(item, 'sortPropertyArray')).toThrow(DwnErrorCode.IndexInvalidCursorValueType);
|
|
1078
|
-
})
|
|
1079
|
-
it('throws if sort property is not defined within the IndexedItem', () =>
|
|
1068
|
+
});
|
|
1069
|
+
it('throws if sort property is not defined within the IndexedItem', async () => {
|
|
1080
1070
|
const item = {
|
|
1081
1071
|
messageCid: 'message-cid',
|
|
1082
1072
|
indexes: {
|
|
@@ -1084,8 +1074,8 @@ describe('IndexLevel', () => {
|
|
|
1084
1074
|
}
|
|
1085
1075
|
};
|
|
1086
1076
|
expect(() => IndexLevel.createCursorFromItem(item, 'unknownProperty')).toThrow(DwnErrorCode.IndexInvalidCursorSortProperty);
|
|
1087
|
-
})
|
|
1088
|
-
it('returns numeric type cursor value', () =>
|
|
1077
|
+
});
|
|
1078
|
+
it('returns numeric type cursor value', async () => {
|
|
1089
1079
|
const item = {
|
|
1090
1080
|
messageCid: 'message-cid',
|
|
1091
1081
|
indexes: {
|
|
@@ -1094,8 +1084,8 @@ describe('IndexLevel', () => {
|
|
|
1094
1084
|
};
|
|
1095
1085
|
const cursor = IndexLevel.createCursorFromItem(item, 'sortProperty');
|
|
1096
1086
|
expect(cursor.value).toBe(1234);
|
|
1097
|
-
})
|
|
1098
|
-
it('returns string type cursor value', () =>
|
|
1087
|
+
});
|
|
1088
|
+
it('returns string type cursor value', async () => {
|
|
1099
1089
|
const item = {
|
|
1100
1090
|
messageCid: 'message-cid',
|
|
1101
1091
|
indexes: {
|
|
@@ -1104,14 +1094,14 @@ describe('IndexLevel', () => {
|
|
|
1104
1094
|
};
|
|
1105
1095
|
const cursor = IndexLevel.createCursorFromItem(item, 'sortProperty');
|
|
1106
1096
|
expect(cursor.value).toBe('1234');
|
|
1107
|
-
})
|
|
1097
|
+
});
|
|
1108
1098
|
});
|
|
1109
1099
|
describe('createCursorFromLastArrayItem', () => {
|
|
1110
|
-
it('returns undefined if an empty array is provided', () =>
|
|
1100
|
+
it('returns undefined if an empty array is provided', async () => {
|
|
1111
1101
|
const cursor = IndexLevel.createCursorFromLastArrayItem([], 'someProperty');
|
|
1112
1102
|
expect(cursor).toBe(undefined);
|
|
1113
|
-
})
|
|
1114
|
-
it('returns a PaginationCursor for the last item given a valid sort property', () =>
|
|
1103
|
+
});
|
|
1104
|
+
it('returns a PaginationCursor for the last item given a valid sort property', async () => {
|
|
1115
1105
|
const items = [{
|
|
1116
1106
|
messageCid: 'cid-1',
|
|
1117
1107
|
indexes: {
|
|
@@ -1128,17 +1118,17 @@ describe('IndexLevel', () => {
|
|
|
1128
1118
|
}
|
|
1129
1119
|
}];
|
|
1130
1120
|
const cursor = IndexLevel.createCursorFromLastArrayItem(items, 'date');
|
|
1131
|
-
expect(cursor
|
|
1132
|
-
expect(cursor
|
|
1133
|
-
})
|
|
1121
|
+
expect(cursor?.messageCid).toBe('cid-2'); // expect the cursor to equal the messageCid
|
|
1122
|
+
expect(cursor?.value).toBe('2023-12-14T11:22:33.000000Z');
|
|
1123
|
+
});
|
|
1134
1124
|
});
|
|
1135
1125
|
describe('encodeValue', () => {
|
|
1136
|
-
it('should wrap string in quotes', () =>
|
|
1126
|
+
it('should wrap string in quotes', async () => {
|
|
1137
1127
|
expect(IndexLevel.encodeValue('test')).toBe(`"test"`);
|
|
1138
|
-
})
|
|
1139
|
-
it('should return string encoded number using encodeNumberValue()', () =>
|
|
1128
|
+
});
|
|
1129
|
+
it('should return string encoded number using encodeNumberValue()', async () => {
|
|
1140
1130
|
expect(IndexLevel.encodeValue(10)).toBe(IndexLevel.encodeNumberValue(10));
|
|
1141
|
-
})
|
|
1131
|
+
});
|
|
1142
1132
|
it('should return stringified boolean', () => {
|
|
1143
1133
|
expect(IndexLevel.encodeValue(true)).toBe('true');
|
|
1144
1134
|
expect(IndexLevel.encodeValue(false)).toBe('false');
|
|
@@ -1170,17 +1160,17 @@ describe('IndexLevel', () => {
|
|
|
1170
1160
|
describe('isFilterConcise', () => {
|
|
1171
1161
|
const queryOptionsWithCursor = { sortProperty: 'sort', cursor: { messageCid: 'messageCid', value: 'value' } };
|
|
1172
1162
|
const queryOptionsWithoutCursor = { sortProperty: 'sort' };
|
|
1173
|
-
it('recordId is always concise', () =>
|
|
1163
|
+
it('recordId is always concise', async () => {
|
|
1174
1164
|
expect(IndexLevel.isFilterConcise({ recordId: 'record-id' }, queryOptionsWithCursor)).toBe(true);
|
|
1175
1165
|
expect(IndexLevel.isFilterConcise({ recordId: 'record-id' }, queryOptionsWithoutCursor)).toBe(true);
|
|
1176
|
-
})
|
|
1177
|
-
it('other than if `recordId` exists, if a cursor exists it is never concise', () =>
|
|
1166
|
+
});
|
|
1167
|
+
it('other than if `recordId` exists, if a cursor exists it is never concise', async () => {
|
|
1178
1168
|
expect(IndexLevel.isFilterConcise({ schema: 'schema', contextId: 'contextId', parentId: 'parentId' }, queryOptionsWithCursor)).toBe(false);
|
|
1179
1169
|
// control
|
|
1180
1170
|
expect(IndexLevel.isFilterConcise({ schema: 'schema', contextId: 'contextId', parentId: 'parentId' }, queryOptionsWithoutCursor)).toBe(true);
|
|
1181
1171
|
expect(IndexLevel.isFilterConcise({ recordId: 'record-id' }, queryOptionsWithCursor)).toBe(true);
|
|
1182
|
-
})
|
|
1183
|
-
it('if there is no cursor - protocolPath, contextId, parentId, or schema return a concise filter', () =>
|
|
1172
|
+
});
|
|
1173
|
+
it('if there is no cursor - protocolPath, contextId, parentId, or schema return a concise filter', async () => {
|
|
1184
1174
|
expect(IndexLevel.isFilterConcise({ protocolPath: 'protocolPath' }, queryOptionsWithoutCursor)).toBe(true);
|
|
1185
1175
|
expect(IndexLevel.isFilterConcise({ protocolPath: 'protocolPath' }, queryOptionsWithCursor)).toBe(false); // control
|
|
1186
1176
|
expect(IndexLevel.isFilterConcise({ contextId: 'contextId' }, queryOptionsWithoutCursor)).toBe(true);
|
|
@@ -1189,17 +1179,17 @@ describe('IndexLevel', () => {
|
|
|
1189
1179
|
expect(IndexLevel.isFilterConcise({ contextId: 'parentId' }, queryOptionsWithCursor)).toBe(false); // control
|
|
1190
1180
|
expect(IndexLevel.isFilterConcise({ contextId: 'schema' }, queryOptionsWithoutCursor)).toBe(true);
|
|
1191
1181
|
expect(IndexLevel.isFilterConcise({ contextId: 'schema' }, queryOptionsWithCursor)).toBe(false); // control
|
|
1192
|
-
})
|
|
1193
|
-
it('if there is no cursor, and it is not one of the conditions, return not concise', () =>
|
|
1182
|
+
});
|
|
1183
|
+
it('if there is no cursor, and it is not one of the conditions, return not concise', async () => {
|
|
1194
1184
|
expect(IndexLevel.isFilterConcise({ dataSize: { gt: 123 } }, queryOptionsWithoutCursor)).toBe(false);
|
|
1195
1185
|
// control
|
|
1196
1186
|
expect(IndexLevel.isFilterConcise({ schema: 'schema', contextId: 'contextId', parentId: 'parentId' }, queryOptionsWithoutCursor)).toBe(true);
|
|
1197
|
-
})
|
|
1198
|
-
it('if protocol filter exists by itself it is not a concise filter', () =>
|
|
1187
|
+
});
|
|
1188
|
+
it('if protocol filter exists by itself it is not a concise filter', async () => {
|
|
1199
1189
|
expect(IndexLevel.isFilterConcise({ protocol: 'protocol' }, queryOptionsWithoutCursor)).toBe(false);
|
|
1200
1190
|
// control
|
|
1201
1191
|
expect(IndexLevel.isFilterConcise({ protocol: 'protocol', protocolPath: 'path/to' }, queryOptionsWithoutCursor)).toBe(true);
|
|
1202
|
-
})
|
|
1192
|
+
});
|
|
1203
1193
|
});
|
|
1204
1194
|
describe('compound indexes', () => {
|
|
1205
1195
|
const compoundIndexes = [
|
|
@@ -1216,24 +1206,24 @@ describe('IndexLevel', () => {
|
|
|
1216
1206
|
];
|
|
1217
1207
|
let compoundIndex;
|
|
1218
1208
|
const compoundTenant = 'did:alice:compound-test';
|
|
1219
|
-
beforeAll(() =>
|
|
1209
|
+
beforeAll(async () => {
|
|
1220
1210
|
compoundIndex = new IndexLevel({
|
|
1221
1211
|
createLevelDatabase,
|
|
1222
1212
|
location: 'TEST-COMPOUND-INDEX',
|
|
1223
1213
|
compoundIndexes: compoundIndexes,
|
|
1224
1214
|
});
|
|
1225
|
-
|
|
1226
|
-
})
|
|
1227
|
-
beforeEach(() =>
|
|
1228
|
-
|
|
1229
|
-
})
|
|
1230
|
-
afterAll(() =>
|
|
1231
|
-
|
|
1232
|
-
})
|
|
1215
|
+
await compoundIndex.open();
|
|
1216
|
+
});
|
|
1217
|
+
beforeEach(async () => {
|
|
1218
|
+
await compoundIndex.clear();
|
|
1219
|
+
});
|
|
1220
|
+
afterAll(async () => {
|
|
1221
|
+
await compoundIndex.close();
|
|
1222
|
+
});
|
|
1233
1223
|
describe('put and delete lifecycle', () => {
|
|
1234
|
-
it('should create compound index entries during put', () =>
|
|
1224
|
+
it('should create compound index entries during put', async () => {
|
|
1235
1225
|
const id = uuid();
|
|
1236
|
-
|
|
1226
|
+
await compoundIndex.put(compoundTenant, id, {
|
|
1237
1227
|
protocol: 'https://protocol.xyz',
|
|
1238
1228
|
protocolPath: 'chat/message',
|
|
1239
1229
|
messageTimestamp: '2024-01-15T10:00:00.000000Z',
|
|
@@ -1241,13 +1231,13 @@ describe('IndexLevel', () => {
|
|
|
1241
1231
|
dateCreated: '2024-01-15T10:00:00.000000Z',
|
|
1242
1232
|
});
|
|
1243
1233
|
// query using compound index (protocol + protocolPath sorted by messageTimestamp)
|
|
1244
|
-
const results =
|
|
1234
|
+
const results = await compoundIndex.query(compoundTenant, [{ protocol: 'https://protocol.xyz', protocolPath: 'chat/message' }], { sortProperty: 'messageTimestamp' });
|
|
1245
1235
|
expect(results.length).toBe(1);
|
|
1246
1236
|
expect(results[0].messageCid).toBe(id);
|
|
1247
|
-
})
|
|
1248
|
-
it('should delete compound index entries during delete', () =>
|
|
1237
|
+
});
|
|
1238
|
+
it('should delete compound index entries during delete', async () => {
|
|
1249
1239
|
const id = uuid();
|
|
1250
|
-
|
|
1240
|
+
await compoundIndex.put(compoundTenant, id, {
|
|
1251
1241
|
protocol: 'https://protocol.xyz',
|
|
1252
1242
|
protocolPath: 'chat/message',
|
|
1253
1243
|
messageTimestamp: '2024-01-15T10:00:00.000000Z',
|
|
@@ -1255,30 +1245,30 @@ describe('IndexLevel', () => {
|
|
|
1255
1245
|
dateCreated: '2024-01-15T10:00:00.000000Z',
|
|
1256
1246
|
});
|
|
1257
1247
|
// verify it exists
|
|
1258
|
-
let results =
|
|
1248
|
+
let results = await compoundIndex.query(compoundTenant, [{ protocol: 'https://protocol.xyz', protocolPath: 'chat/message' }], { sortProperty: 'messageTimestamp' });
|
|
1259
1249
|
expect(results.length).toBe(1);
|
|
1260
1250
|
// delete
|
|
1261
|
-
|
|
1251
|
+
await compoundIndex.delete(compoundTenant, id);
|
|
1262
1252
|
// verify compound index entries are removed
|
|
1263
|
-
results =
|
|
1253
|
+
results = await compoundIndex.query(compoundTenant, [{ protocol: 'https://protocol.xyz', protocolPath: 'chat/message' }], { sortProperty: 'messageTimestamp' });
|
|
1264
1254
|
expect(results.length).toBe(0);
|
|
1265
|
-
})
|
|
1266
|
-
it('should skip compound index entries when required properties are missing', () =>
|
|
1255
|
+
});
|
|
1256
|
+
it('should skip compound index entries when required properties are missing', async () => {
|
|
1267
1257
|
const id = uuid();
|
|
1268
1258
|
// only has schema, not protocol+protocolPath
|
|
1269
|
-
|
|
1259
|
+
await compoundIndex.put(compoundTenant, id, {
|
|
1270
1260
|
schema: 'https://schema.org/Message',
|
|
1271
1261
|
dateCreated: '2024-01-15T10:00:00.000000Z',
|
|
1272
1262
|
});
|
|
1273
1263
|
// the protocol+protocolPath compound index should not have entries
|
|
1274
1264
|
// query via the schema compound index should still work
|
|
1275
|
-
const schemaResults =
|
|
1265
|
+
const schemaResults = await compoundIndex.query(compoundTenant, [{ schema: 'https://schema.org/Message' }], { sortProperty: 'dateCreated' });
|
|
1276
1266
|
expect(schemaResults.length).toBe(1);
|
|
1277
1267
|
expect(schemaResults[0].messageCid).toBe(id);
|
|
1278
|
-
})
|
|
1268
|
+
});
|
|
1279
1269
|
});
|
|
1280
1270
|
describe('queryWithCompoundIndex()', () => {
|
|
1281
|
-
it('should return results sorted ascending by the sort property', () =>
|
|
1271
|
+
it('should return results sorted ascending by the sort property', async () => {
|
|
1282
1272
|
const ids = ['msg-c', 'msg-a', 'msg-b'];
|
|
1283
1273
|
const timestamps = [
|
|
1284
1274
|
'2024-01-15T12:00:00.000000Z',
|
|
@@ -1286,17 +1276,17 @@ describe('IndexLevel', () => {
|
|
|
1286
1276
|
'2024-01-15T11:00:00.000000Z',
|
|
1287
1277
|
];
|
|
1288
1278
|
for (let i = 0; i < ids.length; i++) {
|
|
1289
|
-
|
|
1279
|
+
await compoundIndex.put(compoundTenant, ids[i], {
|
|
1290
1280
|
protocol: 'https://proto.xyz',
|
|
1291
1281
|
protocolPath: 'thread/post',
|
|
1292
1282
|
messageTimestamp: timestamps[i],
|
|
1293
1283
|
});
|
|
1294
1284
|
}
|
|
1295
|
-
const results =
|
|
1285
|
+
const results = await compoundIndex.query(compoundTenant, [{ protocol: 'https://proto.xyz', protocolPath: 'thread/post' }], { sortProperty: 'messageTimestamp' });
|
|
1296
1286
|
expect(results.length).toBe(3);
|
|
1297
1287
|
expect(results.map(r => r.messageCid)).toEqual(['msg-a', 'msg-b', 'msg-c']);
|
|
1298
|
-
})
|
|
1299
|
-
it('should return results sorted descending by the sort property', () =>
|
|
1288
|
+
});
|
|
1289
|
+
it('should return results sorted descending by the sort property', async () => {
|
|
1300
1290
|
const ids = ['msg-c', 'msg-a', 'msg-b'];
|
|
1301
1291
|
const timestamps = [
|
|
1302
1292
|
'2024-01-15T12:00:00.000000Z',
|
|
@@ -1304,68 +1294,68 @@ describe('IndexLevel', () => {
|
|
|
1304
1294
|
'2024-01-15T11:00:00.000000Z',
|
|
1305
1295
|
];
|
|
1306
1296
|
for (let i = 0; i < ids.length; i++) {
|
|
1307
|
-
|
|
1297
|
+
await compoundIndex.put(compoundTenant, ids[i], {
|
|
1308
1298
|
protocol: 'https://proto.xyz',
|
|
1309
1299
|
protocolPath: 'thread/post',
|
|
1310
1300
|
messageTimestamp: timestamps[i],
|
|
1311
1301
|
});
|
|
1312
1302
|
}
|
|
1313
|
-
const results =
|
|
1303
|
+
const results = await compoundIndex.query(compoundTenant, [{ protocol: 'https://proto.xyz', protocolPath: 'thread/post' }], { sortProperty: 'messageTimestamp', sortDirection: SortDirection.Descending });
|
|
1314
1304
|
expect(results.length).toBe(3);
|
|
1315
1305
|
expect(results.map(r => r.messageCid)).toEqual(['msg-c', 'msg-b', 'msg-a']);
|
|
1316
|
-
})
|
|
1317
|
-
it('should support limit', () =>
|
|
1306
|
+
});
|
|
1307
|
+
it('should support limit', async () => {
|
|
1318
1308
|
for (let i = 0; i < 5; i++) {
|
|
1319
|
-
|
|
1309
|
+
await compoundIndex.put(compoundTenant, `msg-${i}`, {
|
|
1320
1310
|
protocol: 'https://proto.xyz',
|
|
1321
1311
|
protocolPath: 'items',
|
|
1322
1312
|
messageTimestamp: `2024-01-15T1${i}:00:00.000000Z`,
|
|
1323
1313
|
});
|
|
1324
1314
|
}
|
|
1325
|
-
const results =
|
|
1315
|
+
const results = await compoundIndex.query(compoundTenant, [{ protocol: 'https://proto.xyz', protocolPath: 'items' }], { sortProperty: 'messageTimestamp', limit: 3 });
|
|
1326
1316
|
expect(results.length).toBe(3);
|
|
1327
1317
|
expect(results.map(r => r.messageCid)).toEqual(['msg-0', 'msg-1', 'msg-2']);
|
|
1328
|
-
})
|
|
1329
|
-
it('should support cursor pagination ascending', () =>
|
|
1318
|
+
});
|
|
1319
|
+
it('should support cursor pagination ascending', async () => {
|
|
1330
1320
|
for (let i = 0; i < 6; i++) {
|
|
1331
|
-
|
|
1321
|
+
await compoundIndex.put(compoundTenant, `msg-${i}`, {
|
|
1332
1322
|
protocol: 'https://proto.xyz',
|
|
1333
1323
|
protocolPath: 'items',
|
|
1334
1324
|
messageTimestamp: `2024-01-15T1${i}:00:00.000000Z`,
|
|
1335
1325
|
});
|
|
1336
1326
|
}
|
|
1337
1327
|
// first page
|
|
1338
|
-
const page1 =
|
|
1328
|
+
const page1 = await compoundIndex.query(compoundTenant, [{ protocol: 'https://proto.xyz', protocolPath: 'items' }], { sortProperty: 'messageTimestamp', limit: 3 });
|
|
1339
1329
|
expect(page1.length).toBe(3);
|
|
1340
1330
|
expect(page1.map(r => r.messageCid)).toEqual(['msg-0', 'msg-1', 'msg-2']);
|
|
1341
1331
|
// second page using cursor
|
|
1342
1332
|
const cursor = IndexLevel.createCursorFromLastArrayItem(page1, 'messageTimestamp');
|
|
1343
|
-
const page2 =
|
|
1333
|
+
const page2 = await compoundIndex.query(compoundTenant, [{ protocol: 'https://proto.xyz', protocolPath: 'items' }], { sortProperty: 'messageTimestamp', cursor });
|
|
1344
1334
|
expect(page2.length).toBe(3);
|
|
1345
1335
|
expect(page2.map(r => r.messageCid)).toEqual(['msg-3', 'msg-4', 'msg-5']);
|
|
1346
|
-
})
|
|
1347
|
-
it('should support cursor pagination descending', () =>
|
|
1336
|
+
});
|
|
1337
|
+
it('should support cursor pagination descending', async () => {
|
|
1348
1338
|
for (let i = 0; i < 6; i++) {
|
|
1349
|
-
|
|
1339
|
+
await compoundIndex.put(compoundTenant, `msg-${i}`, {
|
|
1350
1340
|
protocol: 'https://proto.xyz',
|
|
1351
1341
|
protocolPath: 'items',
|
|
1352
1342
|
messageTimestamp: `2024-01-15T1${i}:00:00.000000Z`,
|
|
1353
1343
|
});
|
|
1354
1344
|
}
|
|
1355
1345
|
// first page descending
|
|
1356
|
-
const page1 =
|
|
1346
|
+
const page1 = await compoundIndex.query(compoundTenant, [{ protocol: 'https://proto.xyz', protocolPath: 'items' }], { sortProperty: 'messageTimestamp', sortDirection: SortDirection.Descending, limit: 3 });
|
|
1357
1347
|
expect(page1.length).toBe(3);
|
|
1358
1348
|
expect(page1.map(r => r.messageCid)).toEqual(['msg-5', 'msg-4', 'msg-3']);
|
|
1359
1349
|
// second page descending using cursor
|
|
1360
1350
|
const cursor = IndexLevel.createCursorFromLastArrayItem(page1, 'messageTimestamp');
|
|
1361
|
-
const page2 =
|
|
1351
|
+
const page2 = await compoundIndex.query(compoundTenant, [{ protocol: 'https://proto.xyz', protocolPath: 'items' }], { sortProperty: 'messageTimestamp', sortDirection: SortDirection.Descending, cursor });
|
|
1362
1352
|
expect(page2.length).toBe(3);
|
|
1363
1353
|
expect(page2.map(r => r.messageCid)).toEqual(['msg-2', 'msg-1', 'msg-0']);
|
|
1364
|
-
})
|
|
1365
|
-
it('should verify residual filter properties in memory', () =>
|
|
1354
|
+
});
|
|
1355
|
+
it('should verify residual filter properties in memory', async () => {
|
|
1366
1356
|
// insert records with same protocol+protocolPath but different 'published' values
|
|
1367
1357
|
for (let i = 0; i < 4; i++) {
|
|
1368
|
-
|
|
1358
|
+
await compoundIndex.put(compoundTenant, `msg-${i}`, {
|
|
1369
1359
|
protocol: 'https://proto.xyz',
|
|
1370
1360
|
protocolPath: 'items',
|
|
1371
1361
|
messageTimestamp: `2024-01-15T1${i}:00:00.000000Z`,
|
|
@@ -1374,56 +1364,56 @@ describe('IndexLevel', () => {
|
|
|
1374
1364
|
}
|
|
1375
1365
|
// compound index covers protocol+protocolPath+messageTimestamp but NOT published
|
|
1376
1366
|
// published should be verified as a residual filter
|
|
1377
|
-
const results =
|
|
1367
|
+
const results = await compoundIndex.query(compoundTenant, [{ protocol: 'https://proto.xyz', protocolPath: 'items', published: true }], { sortProperty: 'messageTimestamp' });
|
|
1378
1368
|
expect(results.length).toBe(2);
|
|
1379
1369
|
expect(results.map(r => r.messageCid)).toEqual(['msg-0', 'msg-2']);
|
|
1380
|
-
})
|
|
1381
|
-
it('should only return results matching the specific filter values', () =>
|
|
1370
|
+
});
|
|
1371
|
+
it('should only return results matching the specific filter values', async () => {
|
|
1382
1372
|
// insert records with different protocol paths
|
|
1383
|
-
|
|
1373
|
+
await compoundIndex.put(compoundTenant, 'msg-1', {
|
|
1384
1374
|
protocol: 'https://proto.xyz',
|
|
1385
1375
|
protocolPath: 'thread/post',
|
|
1386
1376
|
messageTimestamp: '2024-01-15T10:00:00.000000Z',
|
|
1387
1377
|
});
|
|
1388
|
-
|
|
1378
|
+
await compoundIndex.put(compoundTenant, 'msg-2', {
|
|
1389
1379
|
protocol: 'https://proto.xyz',
|
|
1390
1380
|
protocolPath: 'thread/reply',
|
|
1391
1381
|
messageTimestamp: '2024-01-15T11:00:00.000000Z',
|
|
1392
1382
|
});
|
|
1393
|
-
|
|
1383
|
+
await compoundIndex.put(compoundTenant, 'msg-3', {
|
|
1394
1384
|
protocol: 'https://other.xyz',
|
|
1395
1385
|
protocolPath: 'thread/post',
|
|
1396
1386
|
messageTimestamp: '2024-01-15T12:00:00.000000Z',
|
|
1397
1387
|
});
|
|
1398
1388
|
// query for only protocol.xyz + thread/post
|
|
1399
|
-
const results =
|
|
1389
|
+
const results = await compoundIndex.query(compoundTenant, [{ protocol: 'https://proto.xyz', protocolPath: 'thread/post' }], { sortProperty: 'messageTimestamp' });
|
|
1400
1390
|
expect(results.length).toBe(1);
|
|
1401
1391
|
expect(results[0].messageCid).toBe('msg-1');
|
|
1402
|
-
})
|
|
1403
|
-
it('should fall back to non-compound strategy for OR (multi-filter) queries', () =>
|
|
1404
|
-
|
|
1392
|
+
});
|
|
1393
|
+
it('should fall back to non-compound strategy for OR (multi-filter) queries', async () => {
|
|
1394
|
+
await compoundIndex.put(compoundTenant, 'msg-1', {
|
|
1405
1395
|
protocol: 'https://proto.xyz',
|
|
1406
1396
|
protocolPath: 'thread/post',
|
|
1407
1397
|
messageTimestamp: '2024-01-15T10:00:00.000000Z',
|
|
1408
1398
|
});
|
|
1409
|
-
|
|
1399
|
+
await compoundIndex.put(compoundTenant, 'msg-2', {
|
|
1410
1400
|
protocol: 'https://proto.xyz',
|
|
1411
1401
|
protocolPath: 'thread/reply',
|
|
1412
1402
|
messageTimestamp: '2024-01-15T11:00:00.000000Z',
|
|
1413
1403
|
});
|
|
1414
1404
|
// OR queries (multiple filters) should still work via fallback strategies
|
|
1415
|
-
const results =
|
|
1405
|
+
const results = await compoundIndex.query(compoundTenant, [
|
|
1416
1406
|
{ protocol: 'https://proto.xyz', protocolPath: 'thread/post' },
|
|
1417
1407
|
{ protocol: 'https://proto.xyz', protocolPath: 'thread/reply' },
|
|
1418
1408
|
], { sortProperty: 'messageTimestamp' });
|
|
1419
1409
|
expect(results.length).toBe(2);
|
|
1420
|
-
})
|
|
1421
|
-
it('should prefer the compound index with the most properties', () =>
|
|
1410
|
+
});
|
|
1411
|
+
it('should prefer the compound index with the most properties', async () => {
|
|
1422
1412
|
// both compound indexes could potentially match a query with schema + dateCreated
|
|
1423
1413
|
// but only the schema-dateCreated one actually applies
|
|
1424
1414
|
// also, the protocol-protocolPath-messageTimestamp index should be preferred over
|
|
1425
1415
|
// a hypothetical single-property index when both protocol and protocolPath are present
|
|
1426
|
-
|
|
1416
|
+
await compoundIndex.put(compoundTenant, 'msg-1', {
|
|
1427
1417
|
protocol: 'https://proto.xyz',
|
|
1428
1418
|
protocolPath: 'items',
|
|
1429
1419
|
messageTimestamp: '2024-01-15T10:00:00.000000Z',
|
|
@@ -1431,16 +1421,16 @@ describe('IndexLevel', () => {
|
|
|
1431
1421
|
dateCreated: '2024-01-15T10:00:00.000000Z',
|
|
1432
1422
|
});
|
|
1433
1423
|
// query using schema compound index
|
|
1434
|
-
const schemaResults =
|
|
1424
|
+
const schemaResults = await compoundIndex.query(compoundTenant, [{ schema: 'https://schema.org/Item' }], { sortProperty: 'dateCreated' });
|
|
1435
1425
|
expect(schemaResults.length).toBe(1);
|
|
1436
1426
|
expect(schemaResults[0].messageCid).toBe('msg-1');
|
|
1437
1427
|
// query using protocol+protocolPath compound index
|
|
1438
|
-
const protocolResults =
|
|
1428
|
+
const protocolResults = await compoundIndex.query(compoundTenant, [{ protocol: 'https://proto.xyz', protocolPath: 'items' }], { sortProperty: 'messageTimestamp' });
|
|
1439
1429
|
expect(protocolResults.length).toBe(1);
|
|
1440
1430
|
expect(protocolResults[0].messageCid).toBe('msg-1');
|
|
1441
|
-
})
|
|
1442
|
-
it('should not use compound index when sort property does not match', () =>
|
|
1443
|
-
|
|
1431
|
+
});
|
|
1432
|
+
it('should not use compound index when sort property does not match', async () => {
|
|
1433
|
+
await compoundIndex.put(compoundTenant, 'msg-1', {
|
|
1444
1434
|
protocol: 'https://proto.xyz',
|
|
1445
1435
|
protocolPath: 'items',
|
|
1446
1436
|
messageTimestamp: '2024-01-15T10:00:00.000000Z',
|
|
@@ -1450,14 +1440,14 @@ describe('IndexLevel', () => {
|
|
|
1450
1440
|
// query with protocol+protocolPath but sort by dateCreated (not messageTimestamp)
|
|
1451
1441
|
// this should NOT use the protocol-protocolPath-messageTimestamp compound index
|
|
1452
1442
|
// it should still return correct results via fallback strategy
|
|
1453
|
-
const results =
|
|
1443
|
+
const results = await compoundIndex.query(compoundTenant, [{ protocol: 'https://proto.xyz', protocolPath: 'items' }], { sortProperty: 'dateCreated' });
|
|
1454
1444
|
expect(results.length).toBe(1);
|
|
1455
|
-
})
|
|
1445
|
+
});
|
|
1456
1446
|
});
|
|
1457
1447
|
describe('count()', () => {
|
|
1458
|
-
it('should count items matching a compound index filter', () =>
|
|
1448
|
+
it('should count items matching a compound index filter', async () => {
|
|
1459
1449
|
for (let i = 0; i < 10; i++) {
|
|
1460
|
-
|
|
1450
|
+
await compoundIndex.put(compoundTenant, `msg-${i}`, {
|
|
1461
1451
|
protocol: 'https://proto.xyz',
|
|
1462
1452
|
protocolPath: 'items',
|
|
1463
1453
|
messageTimestamp: `2024-01-15T1${i}:00:00.000000Z`,
|
|
@@ -1465,39 +1455,39 @@ describe('IndexLevel', () => {
|
|
|
1465
1455
|
}
|
|
1466
1456
|
// add some non-matching records
|
|
1467
1457
|
for (let i = 0; i < 5; i++) {
|
|
1468
|
-
|
|
1458
|
+
await compoundIndex.put(compoundTenant, `other-${i}`, {
|
|
1469
1459
|
protocol: 'https://other.xyz',
|
|
1470
1460
|
protocolPath: 'items',
|
|
1471
1461
|
messageTimestamp: `2024-01-15T1${i}:00:00.000000Z`,
|
|
1472
1462
|
});
|
|
1473
1463
|
}
|
|
1474
|
-
const count =
|
|
1464
|
+
const count = await compoundIndex.count(compoundTenant, [{ protocol: 'https://proto.xyz', protocolPath: 'items' }], { sortProperty: 'messageTimestamp' });
|
|
1475
1465
|
expect(count).toBe(10);
|
|
1476
|
-
})
|
|
1477
|
-
it('should count items with residual filter verification', () =>
|
|
1466
|
+
});
|
|
1467
|
+
it('should count items with residual filter verification', async () => {
|
|
1478
1468
|
for (let i = 0; i < 6; i++) {
|
|
1479
|
-
|
|
1469
|
+
await compoundIndex.put(compoundTenant, `msg-${i}`, {
|
|
1480
1470
|
protocol: 'https://proto.xyz',
|
|
1481
1471
|
protocolPath: 'items',
|
|
1482
1472
|
messageTimestamp: `2024-01-15T1${i}:00:00.000000Z`,
|
|
1483
1473
|
published: i % 2 === 0, // msg-0: true, msg-1: false, msg-2: true, msg-3: false, msg-4: true, msg-5: false
|
|
1484
1474
|
});
|
|
1485
1475
|
}
|
|
1486
|
-
const count =
|
|
1476
|
+
const count = await compoundIndex.count(compoundTenant, [{ protocol: 'https://proto.xyz', protocolPath: 'items', published: true }], { sortProperty: 'messageTimestamp' });
|
|
1487
1477
|
expect(count).toBe(3); // msg-0, msg-2, msg-4
|
|
1488
|
-
})
|
|
1489
|
-
it('should return 0 when no items match', () =>
|
|
1490
|
-
|
|
1478
|
+
});
|
|
1479
|
+
it('should return 0 when no items match', async () => {
|
|
1480
|
+
await compoundIndex.put(compoundTenant, 'msg-1', {
|
|
1491
1481
|
protocol: 'https://proto.xyz',
|
|
1492
1482
|
protocolPath: 'items',
|
|
1493
1483
|
messageTimestamp: '2024-01-15T10:00:00.000000Z',
|
|
1494
1484
|
});
|
|
1495
|
-
const count =
|
|
1485
|
+
const count = await compoundIndex.count(compoundTenant, [{ protocol: 'https://nonexistent.xyz', protocolPath: 'items' }], { sortProperty: 'messageTimestamp' });
|
|
1496
1486
|
expect(count).toBe(0);
|
|
1497
|
-
})
|
|
1498
|
-
it('should fall back to full query for non-compound-index filters', () =>
|
|
1487
|
+
});
|
|
1488
|
+
it('should fall back to full query for non-compound-index filters', async () => {
|
|
1499
1489
|
for (let i = 0; i < 4; i++) {
|
|
1500
|
-
|
|
1490
|
+
await compoundIndex.put(compoundTenant, `msg-${i}`, {
|
|
1501
1491
|
protocol: 'https://proto.xyz',
|
|
1502
1492
|
protocolPath: 'items',
|
|
1503
1493
|
messageTimestamp: `2024-01-15T1${i}:00:00.000000Z`,
|
|
@@ -1505,53 +1495,53 @@ describe('IndexLevel', () => {
|
|
|
1505
1495
|
});
|
|
1506
1496
|
}
|
|
1507
1497
|
// filter by 'published' alone — no compound index covers this
|
|
1508
|
-
const count =
|
|
1498
|
+
const count = await compoundIndex.count(compoundTenant, [{ published: true }], { sortProperty: 'messageTimestamp' });
|
|
1509
1499
|
expect(count).toBe(2);
|
|
1510
|
-
})
|
|
1511
|
-
it('should count correctly with OR (multi-filter) queries', () =>
|
|
1512
|
-
|
|
1500
|
+
});
|
|
1501
|
+
it('should count correctly with OR (multi-filter) queries', async () => {
|
|
1502
|
+
await compoundIndex.put(compoundTenant, 'msg-1', {
|
|
1513
1503
|
protocol: 'https://proto.xyz',
|
|
1514
1504
|
protocolPath: 'thread/post',
|
|
1515
1505
|
messageTimestamp: '2024-01-15T10:00:00.000000Z',
|
|
1516
1506
|
});
|
|
1517
|
-
|
|
1507
|
+
await compoundIndex.put(compoundTenant, 'msg-2', {
|
|
1518
1508
|
protocol: 'https://proto.xyz',
|
|
1519
1509
|
protocolPath: 'thread/reply',
|
|
1520
1510
|
messageTimestamp: '2024-01-15T11:00:00.000000Z',
|
|
1521
1511
|
});
|
|
1522
|
-
|
|
1512
|
+
await compoundIndex.put(compoundTenant, 'msg-3', {
|
|
1523
1513
|
protocol: 'https://other.xyz',
|
|
1524
1514
|
protocolPath: 'thread/post',
|
|
1525
1515
|
messageTimestamp: '2024-01-15T12:00:00.000000Z',
|
|
1526
1516
|
});
|
|
1527
1517
|
// OR query — compound index can't serve this, falls back
|
|
1528
|
-
const count =
|
|
1518
|
+
const count = await compoundIndex.count(compoundTenant, [
|
|
1529
1519
|
{ protocol: 'https://proto.xyz', protocolPath: 'thread/post' },
|
|
1530
1520
|
{ protocol: 'https://proto.xyz', protocolPath: 'thread/reply' },
|
|
1531
1521
|
], { sortProperty: 'messageTimestamp' });
|
|
1532
1522
|
expect(count).toBe(2);
|
|
1533
|
-
})
|
|
1523
|
+
});
|
|
1534
1524
|
});
|
|
1535
1525
|
describe('query() dispatch selects compound index when available', () => {
|
|
1536
|
-
it('should use compound index for matching single-filter queries with cursor', () =>
|
|
1526
|
+
it('should use compound index for matching single-filter queries with cursor', async () => {
|
|
1537
1527
|
// compound indexes support cursors natively, unlike in-memory paging
|
|
1538
1528
|
// which would normally reject a cursor with "concise" filters
|
|
1539
1529
|
for (let i = 0; i < 6; i++) {
|
|
1540
|
-
|
|
1530
|
+
await compoundIndex.put(compoundTenant, `msg-${i}`, {
|
|
1541
1531
|
schema: 'https://schema.org/Item',
|
|
1542
1532
|
dateCreated: `2024-01-15T1${i}:00:00.000000Z`,
|
|
1543
1533
|
});
|
|
1544
1534
|
}
|
|
1545
1535
|
// first page
|
|
1546
|
-
const page1 =
|
|
1536
|
+
const page1 = await compoundIndex.query(compoundTenant, [{ schema: 'https://schema.org/Item' }], { sortProperty: 'dateCreated', limit: 3 });
|
|
1547
1537
|
expect(page1.length).toBe(3);
|
|
1548
1538
|
expect(page1.map(r => r.messageCid)).toEqual(['msg-0', 'msg-1', 'msg-2']);
|
|
1549
1539
|
// second page with cursor — this should still use the compound index
|
|
1550
1540
|
const cursor = IndexLevel.createCursorFromLastArrayItem(page1, 'dateCreated');
|
|
1551
|
-
const page2 =
|
|
1541
|
+
const page2 = await compoundIndex.query(compoundTenant, [{ schema: 'https://schema.org/Item' }], { sortProperty: 'dateCreated', cursor });
|
|
1552
1542
|
expect(page2.length).toBe(3);
|
|
1553
1543
|
expect(page2.map(r => r.messageCid)).toEqual(['msg-3', 'msg-4', 'msg-5']);
|
|
1554
|
-
})
|
|
1544
|
+
});
|
|
1555
1545
|
});
|
|
1556
1546
|
});
|
|
1557
1547
|
});
|